1 4 5 9 10 package org.openlaszlo.servlets.responders; 11 12 import java.io.*; 13 import java.net.UnknownHostException ; 14 import java.net.MalformedURLException ; 15 import java.net.URL ; 16 import java.util.Properties ; 17 import java.util.HashMap ; 18 import java.util.Iterator ; 19 import javax.servlet.ServletConfig ; 20 import javax.servlet.ServletException ; 21 import javax.servlet.http.HttpServletRequest ; 22 import javax.servlet.http.HttpServletResponse ; 23 import javax.servlet.ServletOutputStream ; 24 import org.openlaszlo.cache.RequestCache; 25 import org.openlaszlo.data.*; 26 import org.openlaszlo.media.MimeType; 27 import org.openlaszlo.server.LPS; 28 import org.openlaszlo.utils.LZHttpUtils; 29 import org.openlaszlo.utils.ChainedException; 30 import org.openlaszlo.xml.internal.XMLUtils; 31 import org.apache.commons.httpclient.URI; 32 import org.apache.commons.httpclient.URIException; 33 import org.apache.log4j.Logger; 34 35 public abstract class ResponderCache extends Responder 36 { 37 private static boolean mIsInitialized = false; 38 39 private static HashMap mDataSourceMap = new HashMap (); 40 private static DataSource mHTTPDataSource = null; 41 42 private static Logger mLogger = Logger.getLogger(ResponderCache.class); 43 44 protected RequestCache mCache = null; 45 46 49 public class URLStat 50 { 51 String mName; 52 53 final static public int ERRTYPE_NONE = -1; 54 final static public int ERRTYPE_CONVERSION = 0; 55 final static public int ERRTYPE_DATA_SOURCE = 1; 56 final static public int ERRTYPE_UNKNOWN_HOST = 2; 57 final static public int ERRTYPE_MALFORMED_URL = 3; 58 final static public int ERRTYPE_IO = 4; 59 final static public int ERRTYPE_ILLEGAL_ARGUMENT = 5; 60 final static public int ERRTYPE_TIMEOUT = 6; 61 final static public int ERRTYPE_FORBIDDEN = 7; 62 final static public int ERRTYPE_OTHER = 8; 63 final static public int NUM_ERRTYPES = 9; 64 65 66 HashMap mURLs = new HashMap (); 67 HashMap mErrorURLs = new HashMap (); 68 69 int mSuccessCount; 70 75 int[] mErrorCount = new int[NUM_ERRTYPES]; 76 77 78 boolean mDoURLCollection = false; 79 80 81 84 public URLStat(String name) 85 { 86 mName = name; 87 clear(); 88 } 89 90 94 void doURLCollection(boolean doCollection) 95 { 96 if (mDoURLCollection != doCollection) { 97 mDoURLCollection = doCollection; 98 clear(); 99 } 100 } 101 102 106 void success(String url) 107 { 108 int x = url.indexOf('?'); 109 if (x != -1) { 110 url = url.substring(0, x); 111 } 112 synchronized (mURLs) { 113 if (mDoURLCollection) { 114 int[] s = (int[]) mURLs.get(url); 116 if (s == null) { 117 s = new int[1]; 118 mURLStat.mURLs.put(url, s); 119 } 120 ++s[0]; 121 } 122 ++mSuccessCount; 123 } 124 } 125 126 127 133 void error(int errType, String url) 134 { 135 int x = url.indexOf('?'); 136 if (x != -1) { 137 url = url.substring(0, x); 138 } 139 synchronized (mErrorURLs) { 140 if (mDoURLCollection) { 141 int[] e = (int[]) mErrorURLs.get(url); 142 if (e == null) { 143 e = new int[NUM_ERRTYPES]; 144 mErrorURLs.put(url, e); 145 } 146 ++e[errType]; 147 } 148 ++mErrorCount[errType]; 149 } 150 151 } 152 153 156 void clear() 157 { 158 synchronized (mURLs) { 159 mURLs.clear(); 160 mSuccessCount = 0; 161 } 162 163 synchronized (mErrorURLs) { 164 mErrorURLs.clear(); 165 for (int i=0; i < mErrorCount.length; i++) 166 mErrorCount[i] = 0; 167 } 168 } 169 170 174 public String toXML() 175 { 176 StringBuffer buf = new StringBuffer (); 177 synchronized (mURLs) { 178 buf.append("<").append(mName).append("-urls ") 179 .append(" unique=\"").append(mURLs.size()).append("\"") 180 .append(">\n"); 181 182 buf.append("<success") 183 .append(" total-requests=\"").append(mSuccessCount).append("\"") 184 .append(">\n"); 185 if (mDoURLCollection) 186 { 187 Iterator iter = mURLs.keySet().iterator(); 188 while (iter.hasNext()) { 189 String k = (String )iter.next(); 190 int[] success = (int[])mURLs.get(k); 191 buf.append("<url") 192 .append(" requests=\"").append(success[0]).append("\"") 193 .append(" HREF=\"").append(XMLUtils.escapeXml(k)).append("\" />"); 194 } 195 } 196 buf.append("</success>\n"); 197 } 198 199 synchronized (mErrorURLs) { 200 int errTotal = 0; 201 for (int i=0; i < mErrorCount.length; i++) 202 errTotal += mErrorCount[i]; 203 buf.append("<errors") 204 .append(" total-errors=\"").append(errTotal).append("\"") 205 .append(" conversion=\"").append(mErrorCount[ERRTYPE_CONVERSION]).append("\"") 206 .append(" datasource=\"").append(mErrorCount[ERRTYPE_DATA_SOURCE]).append("\"") 207 .append(" unknownhost=\"").append(mErrorCount[ERRTYPE_UNKNOWN_HOST]).append("\"") 208 .append(" malformedurl=\"").append(mErrorCount[ERRTYPE_MALFORMED_URL]).append("\"") 209 .append(" ioexception=\"").append(mErrorCount[ERRTYPE_IO]).append("\"") 210 .append(" illegalargument=\"").append(mErrorCount[ERRTYPE_ILLEGAL_ARGUMENT]).append("\"") 211 .append(" timeout=\"").append(mErrorCount[ERRTYPE_TIMEOUT]).append("\"") 212 .append(" forbidden=\"").append(mErrorCount[ERRTYPE_FORBIDDEN]).append("\"") 213 .append(" uncaught-exception=\"").append(mErrorCount[ERRTYPE_OTHER]).append("\"") 214 .append(">\n"); 215 if (mDoURLCollection) 216 { 217 Iterator iter = mErrorURLs.keySet().iterator(); 218 while (iter.hasNext()) { 219 String k = (String )iter.next(); 220 int[] e = (int[])mErrorURLs.get(k); 221 buf.append("<url") 222 .append(" conversion=\"").append(e[ERRTYPE_CONVERSION]).append("\"") 223 .append(" datasource=\"").append(e[ERRTYPE_DATA_SOURCE]).append("\"") 224 .append(" unknownhost=\"").append(e[ERRTYPE_UNKNOWN_HOST]).append("\"") 225 .append(" malformedurl=\"").append(e[ERRTYPE_MALFORMED_URL]).append("\"") 226 .append(" ioexception=\"").append(e[ERRTYPE_IO]).append("\"") 227 .append(" illegalargument=\"").append(e[ERRTYPE_ILLEGAL_ARGUMENT]).append("\"") 228 .append(" timeout=\"").append(e[ERRTYPE_TIMEOUT]).append("\"") 229 .append(" forbidden=\"").append(e[ERRTYPE_FORBIDDEN]).append("\"") 230 .append(" uncaught-exception=\"").append(e[ERRTYPE_OTHER]).append("\"") 231 .append(" HREF=\"").append(XMLUtils.escapeXml(k)).append("\"") 232 .append(" />\n"); 233 } 234 } 235 buf.append("</errors>\n"); 236 } 237 238 buf.append("</").append(mName).append("-urls>\n"); 239 240 return buf.toString(); 241 } 242 } 243 244 public URLStat mURLStat = null; 245 246 synchronized public void init(String reqName, ServletConfig config, 247 RequestCache cache, Properties prop) 248 throws ServletException , IOException 249 { 250 super.init(reqName, config, prop); 251 252 String reqProp = reqName.toLowerCase() + "Request.collectURL"; 253 boolean doURLCollection = 254 prop.getProperty(reqProp, "false").intern() == "true"; 255 256 mURLStat = new URLStat(reqName); 257 mURLStat.doURLCollection(doURLCollection); 258 259 if (! mIsInitialized) { 260 mHTTPDataSource = new HTTPDataSource(); 264 265 mDataSourceMap.put("http", mHTTPDataSource); 266 267 mDataSourceMap.put("file", mHTTPDataSource); 269 270 277 278 try { 279 mDataSourceMap.put("java", new JavaDataSource()); 280 } catch (Throwable e) { 281 mLogger.warn("can't load java datasource", e); 282 } 283 284 try { 285 mDataSourceMap.put("soap", new SOAPDataSource()); 286 } catch (Throwable e) { 287 mLogger.warn("can't load soap datasource", e); 288 } 289 290 try { 291 mDataSourceMap.put("xmlrpc", new XMLRPCDataSource()); 292 } catch (Throwable e) { 293 mLogger.warn("can't load xmlrpc datasource", e); 294 } 295 296 mIsInitialized = true; 297 } 298 299 mCache = cache; 300 } 301 302 protected void respondImpl(HttpServletRequest req, HttpServletResponse res) { 303 304 try { 305 req.setCharacterEncoding("UTF-8"); 306 } catch (Exception e) { } 307 308 String path = req.getServletPath(); 309 String url; 310 try { 311 url = DataSource.getURL(req); 312 } catch (java.net.MalformedURLException e) { 313 respondWithErrorSWF(res, "bad url: " + e.getMessage()); 314 if (mCollectStat) { 315 mURLStat.error(URLStat.ERRTYPE_MALFORMED_URL, "bad-url"); 316 } 317 return; 318 } 319 320 if (path.endsWith(".lzo")) { 321 path = path.substring(0, path.length() - 1) + "x"; 322 } 323 324 if (req.getMethod().intern() == "POST") { 325 float fpv = getFlashPlayerVersion(req); 326 String ua = req.getHeader(LZHttpUtils.USER_AGENT); 327 mLogger.debug("POST request, flash player version: " + fpv); 328 if (fpv < 6.47 && 329 LPS.configuration.optionAllows("disable-post-keep-alive", ua)) { 330 mLogger.debug("Disabling keep-alive for " + ua); 332 res.setHeader("Connection", "close"); 333 res.setHeader("Keep-Alive", "close"); 334 } 335 } 336 337 if ( ! LPS.configuration.optionAllows(path, "proxy-security-urls", url) ) { 338 String err = "Forbidden url: " + url; 339 respondWithError(res, err, HttpServletResponse.SC_FORBIDDEN); 340 mLogger.error(err); 341 if (mCollectStat) { 342 mURLStat.error(URLStat.ERRTYPE_FORBIDDEN, url); 343 } 344 return; 345 } 346 347 int errType = URLStat.ERRTYPE_NONE; 348 349 try { 350 351 DataSource source = getDataSource(req, res); 352 if (source == null) { 353 return; 354 } 355 356 res.setContentType(MimeType.SWF); 357 358 String app = LZHttpUtils.getRealPath(mContext, req); 359 boolean isClientCacheable = DataSource.isClientCacheable(req); 360 if (mCache.isCacheable(req)) { 361 if (isClientCacheable) { 362 mLogger.info("proxying " + url + ", cacheable on server and client"); 363 } else { 364 mLogger.info("proxying " + url + ", cacheable on server and not client"); 365 } 366 mCache.getAsSWF(app, req, res, source); 367 } else { 368 if (isClientCacheable) { 369 mLogger.info("proxying " + url + ", not cacheable on server and cacheable on the client"); 370 } else { 371 mLogger.info("proxying " + url + ", not cacheable on server or client"); 372 } 373 source.getAsSWF(app, req, res, getConverter()); 374 } 375 } catch (ConversionException e) { 376 respondWithErrorSWF(res, "data conversion error for " + url + 377 ": " + e.getMessage()); 378 errType = URLStat.ERRTYPE_CONVERSION; 379 } catch (DataSourceException e) { 380 respondWithErrorSWF(res, "data source error for " + url + 381 ": " + e.getMessage()); 382 errType = URLStat.ERRTYPE_DATA_SOURCE; 383 } catch (UnknownHostException e) { 384 respondWithErrorSWF(res, "unknown host for " + url + 385 ": " + e.getMessage()); 386 errType = URLStat.ERRTYPE_UNKNOWN_HOST; 387 } catch (URIException e) { 388 respondWithErrorSWF(res, "bad url: " + e.getMessage()); 389 errType = URLStat.ERRTYPE_MALFORMED_URL; 390 } catch (MalformedURLException e) { 391 respondWithErrorSWF(res, "bad url: " + e.getMessage()); 392 errType = URLStat.ERRTYPE_MALFORMED_URL; 393 } catch (InterruptedIOException e) { 394 respondWithErrorSWF(res, "backend timeout for " + url + 395 ": " + e.getMessage()); 396 errType = URLStat.ERRTYPE_TIMEOUT; 397 } catch (IOException e) { 398 Class stec = null; 400 try { 401 stec = Class.forName("java.net.SocketTimeoutException"); 402 } catch (ClassNotFoundException cfne) { 403 } 404 if (stec != null && stec.isAssignableFrom(e.getClass())) { 405 errType = URLStat.ERRTYPE_TIMEOUT; 406 respondWithErrorSWF(res, "backend timeout for " + url + 407 ": " + e.getMessage()); 408 } else { 409 respondWithExceptionSWF(res, e); 410 errType = URLStat.ERRTYPE_IO; 411 } 412 } catch (IllegalArgumentException e) { 413 respondWithExceptionSWF(res, e); 414 errType = URLStat.ERRTYPE_ILLEGAL_ARGUMENT; 415 } catch (Throwable e) { 416 respondWithExceptionSWF(res, e); 419 errType = URLStat.ERRTYPE_OTHER; 420 } 421 422 if (mCollectStat) { 423 if (errType == URLStat.ERRTYPE_NONE) 424 mURLStat.success(url); 425 else 426 mURLStat.error(errType, url); 427 } 428 } 429 430 433 protected DataSource getDataSource(HttpServletRequest req, 434 HttpServletResponse res) 435 throws MalformedURLException , URIException 436 { 437 String ds = "http"; 438 String urlstr = DataSource.getURL(req); 439 if (urlstr != null) { 440 mLogger.debug("urlstr " + urlstr); 441 URI uri = LZHttpUtils.newURI(urlstr); 442 String protocol = uri.getScheme(); 443 if (protocol != null && protocol.equals("https")) { 444 protocol = "http"; 445 } 446 447 ds = protocol; 448 } 449 450 mLogger.debug("ds is " + ds); 451 452 DataSource source = null; 453 if (ds == null) { 454 source = mHTTPDataSource; 455 } else { 456 source = (DataSource) mDataSourceMap.get(ds); 457 if (source == null) 458 respondWithErrorSWF(res, "Can't find a data source for " + urlstr); 459 } 460 return source; 461 } 462 463 public int getMimeType() 464 { 465 return MIME_TYPE_SWF; 466 } 467 468 public float getFlashPlayerVersion(HttpServletRequest req) { 469 float fpv = (float)-1.0; 470 try { 471 String _fpv = req.getParameter("fpv"); 472 if (_fpv != null) 473 fpv = Float.parseFloat(_fpv); 474 } catch (NumberFormatException e) { 475 mLogger.debug(e.getMessage()); 476 } 477 return fpv; 478 } 479 480 483 public Converter getConverter() { 484 return mCache.getConverter(); 485 } 486 } 487 | Popular Tags |