cachefilter.java
来自「很棒的web服务器源代码」· Java 代码 · 共 892 行 · 第 1/2 页
JAVA
892 行
URL _ru = request.getURL(); String requrl = URLUtils.normalize(_ru).toExternalForm(); // in the pre-cache, wait for full download // FIXME should be better than this behaviour... // see EntityCachedResource perform's FIXME ;) if (precache.containsKey(requrl)) { if (debug) System.out.println("*** Already downloading: "+ requrl); try { CachedResource cr = (CachedResource)precache.get(requrl); return cr.perform(request); } catch (Exception ex) { // there was a problem with the previous request, // it may be better to do it by ourself } } CachedResource res = null; try { res = store.getCachedResourceReference(requrl); } catch (InvalidCacheException ex) { res = null; } // are we disconnected? if (request.checkOnlyIfCached() || !connected ) { // and no entries... EntityCachedResource ecr = null; if (res != null) { ecr = (EntityCachedResource) res.lookupResource(request); } if ((res == null) || (ecr == null)) { if ( debug ) trace(request, "unavailable (disconnected)."); Reply reply = request.makeReply(HTTP.GATEWAY_TIMEOUT); reply.setContent("The cache doesn't have an entry for " + "<p><strong>"+request.getURL()+"</strong>" + ". <p>And it is disconnected."); return reply; } // yeah! if (debug) { trace(request, (connected) ? " hit - only if cached" : " hit while disconneced" ); } if (!validator.isValid(ecr, request)) { addWarning(request, WARN_STALE); } addWarning(request, WARN_DISCONNECTED); Reply reply = ecr.perform(request); // Add any warnings collected during processing to the reply: setWarnings(request, reply);//FIXME request.setState(STATE_HOW, HOW_HIT); return reply; } // in connected mode, we should now take care of revalidation and such if (res != null) { // if not fully loaded, ask for a revalidation FIXME if ((res.getLoadState() == CachedResource.STATE_LOAD_PARTIAL) || (res.getLoadState() == CachedResource.STATE_LOAD_ERROR)) { setRequestRevalidation(res, request); return null; } if ( validator.isValid(res, request) ) { try { store.updateResourceGeneration(res); } catch (InvalidCacheException ex) { // should be ok so... }//FIXME request.setState(STATE_HOW, HOW_HIT); Reply rep = res.perform(request); return rep; } else { if (debug) { System.out.println("*** Revalidation asked for " + requrl); } // ask for a revalidation setRequestRevalidation(res, request); return null; } } // lock here while we are waiting for the download while (uritable.containsKey(requrl)) { synchronized (uritable) { try { uritable.wait(); } catch (InterruptedException ex) {} } if (precache.containsKey(requrl)) { if (debug) System.out.println("*** Already downloading: "+ requrl); CachedResource cr = (CachedResource)precache.get(requrl); return cr.perform(request); } uritable.put(requrl, requrl); } return null; } /** * This filter handle exceptions. * @param request The request that triggered the exception. * @param ex The triggered exception. * @return Always <strong>false</strong>. */ public boolean exceptionFilter(Request request, HttpException ex) { URL _ru; _ru = request.getURL(); String requrl = URLUtils.normalize(_ru).toExternalForm(); synchronized (uritable) { uritable.remove(requrl); uritable.notifyAll(); } return false; } /** * The request post-processing hook. * After each request has been replied to by the target server (be it a * proxy or the actual origin server), each filter's outgoingFilter * method is called. * <p>It gets the original request, and the actual reply as a parameter, * and should return whatever reply it wants the caller to get. * @param request The original (handled) request. * @param reply The reply, as emited by the target server, or constructed * by some other filter. * @exception HttpException If the reply emitted by the server is not * a valid HTTP reply. */ public Reply outgoingFilter(Request request, Reply reply) throws HttpException { URL url = URLUtils.normalize(request.getURL()); // Yeah ! We win: CachedResource c; c = (CachedResource) request.getState(CacheState.STATE_RESOURCE); if ( c != null ) { if ( debug ) trace(request, "revalidated "+reply.getStatus());// request.setState(STATE_HOW// , ((reply.getStatus() == HTTP.NOT_MODIFIED)// ? HOW_REVALIDATION_SUCCESS// : HOW_REVALIDATION_FAILURE));// Reply valrep = c.validate(request, reply); // Client or Server error, ask for revalidation// if (valrep.getStatus()/100 >= 4) {// c.setWillRevalidate(true);// } if (reply.getStatus() == HTTP.NOT_MODIFIED) { // FIXME revalidateResource(request, reply) validator.revalidateResource(c, request, reply); try { store.storeCachedResource(c, c.getCurrentLength()); } catch (InvalidCacheException ex) { if (debug) { ex.printStackTrace(); } } // extract the original request Request origreq; origreq = (Request) request.getState(CacheState.STATE_ORIGREQ); return c.perform(origreq); } else { // delete it c.delete(); store.getState().notifyResourceDeleted(c); } } // don't use cache, exit asap if (!canCache(request, reply)) { request.setState(STATE_NOCACHE, Boolean.TRUE); if (debug) { System.out.println("*** Can't cache reply"); } String requrl = url.toExternalForm(); precache.remove(requrl); synchronized (uritable) { uritable.remove(requrl); uritable.notifyAll(); } invalidateOnReply(request, reply); return null; } if (!canStore(request, reply)) {// request.setState(STATE_NOSTORE, Boolean.TRUE); if (debug) { System.out.println("*** Can't store reply"); } String requrl = url.toExternalForm(); precache.remove(requrl); synchronized (uritable) { uritable.remove(requrl); uritable.notifyAll(); } invalidateOnReply(request, reply); return null; } pushDocument(request, reply); return null; } private void invalidateOnReply(Request request, Reply reply) { URL url = request.getURL(); // now invalidate the entities per rfc2616#13.11 if ((request.getMethod() == HTTP.POST) || (request.getMethod() == HTTP.PUT) || (request.getMethod() == HTTP.DELETE)) { String rloc = reply.getLocation(); String rcloc = reply.getContentLocation(); URL urloc, urcloc; // FIXME use a private method instead of duplicating if (rloc != null) { try { urloc = new URL(rloc); // only if host match if (URLUtils.equalsProtocolHostPort(url,urloc)) { CachedResource res = null; try { res = store.getCachedResourceReference(rloc); if (res != null) { res.setWillRevalidate(true); } } catch (InvalidCacheException ex) { // weird, but it won't stop us :) } } } catch (MalformedURLException mule) { // nothing to do } } if (rcloc != null) { try { urcloc = new URL(url, rcloc); // only if host match if (URLUtils.equalsProtocolHostPort(url,urcloc)) { CachedResource res = null; try { String surcloc = urcloc.toExternalForm(); res = store.getCachedResourceReference(surcloc); if (res != null) { res.setWillRevalidate(true); } } catch (InvalidCacheException ex) { // weird, but it won't stop us :) } } } catch (MalformedURLException mule) { // nothing to do } } } } public void sync() { if (debug) { System.out.println("*** Synching the CacheFilter"); } try { store.sync(); } catch (Exception ex) { System.err.println(getClass().getName()+": Unable to save cache."); } } /** * Property monitoring for the CacheFilter. * The CacheFilter allows you to dynamically (typically through the * property setter) change the class of the sweeper, the validator, * the size... * @param name The name of the property that has changed. * @return A boolean, <strong>true</strong> if the change was made, * <strong>false</strong> otherwise. */ public boolean propertyChanged(String name) { if ( name.equals(SERIALIZER_P) ) { CacheSerializer cs = null; try { Class c; c = Class.forName(props.getString(name, null)); cs = (CacheSerializer) c.newInstance(); } catch (Exception ex) { return false; } serializer = cs; return true; } else if ( name.equals(SWEEPER_P) ) { CacheSweeper cs = null; try { Class c; c = Class.forName(props.getString(name, null)); cs = (CacheSweeper) c.newInstance(); } catch (Exception ex) { return false; } // looks good, let's restart with this one! sweeper.destroy(); sweeper = cs; sweeper.start(); return true; } else if ( name.equals(VALIDATOR_P) ) { CacheValidator cv = null; try { Class c; c = Class.forName(props.getString(name, null)); cv = (CacheValidator) c.newInstance(); } catch (Exception ex) { return false; } validator = cv; return true; } else if ( name.equals(DEBUG_P) ) { debug = props.getBoolean(name, debug); return true; } else if ( name.equals(SHARED_P) ) { shared = props.getBoolean(name, shared); return true; } else if ( name.equals(CACHE_CONNECTED_P)) { connected = props.getBoolean(name, true); return true; } // ask the store if it can do something return store.propertyChanged(name); } /** * Push a document in the cache. * The caller has to forge a a request and a reply before being able * to make something * enter the cache. * The request should provide at least: * <dl> * <dt>URL<dl>The URL (key for cache lookups) * <dt>Method<dl>The method that was "applied" to URL to get forged * reply. * </dl> * <p>It is recommended that the reply provides at least * the following informations: * <dl> * <dt>Status Code</dl>A valid HTTP/1.1 status code (probably <strong> * 200</code>) * <dt>InputStream<dl>Containing the entity to be cached, * <dt>EntityTag<dl>A valid entity tag for the document, * <dt>CacheControl<dl>Appropriate HTTP/1.1 cache controls for that * document, * <dt>Mime headers<dl>At least a valid content type, and probably a * content length (to check consistency with the reply body). * </dt> */ public void pushDocument(Request request, Reply reply) { URL url = URLUtils.normalize(request.getURL()); try { synchronized (uritable) { CachedResource r = null; String requrl = url.toExternalForm(); r = CachedResourceFactory.createResource(this, request, reply); if (r.uploading) precache.put(requrl, r); uritable.remove(requrl); uritable.notifyAll(); } if ( debug ) trace(request, "enters cache."); } catch (Exception ex) { ex.printStackTrace(); } } /** * do what is needed when an upload is done! * ie: remove from the precache and put in the store * @param the CachedResource to be moved. */ protected synchronized void cleanUpload(CachedResource cr) { // FIXME we should check the state! precache.remove(cr.getIdentifier()); try { store.storeCachedResource(cr); } catch (InvalidCacheException ex) { if (debug) { ex.printStackTrace(); } } } /** * @return the store used a CacheStore */ public CacheStore getStore() { return store; } public void initialize(HttpManager manager) throws PropRequestFilterException { String validator_c; String sweeper_c; String serializer_c; props = manager.getProperties(); shared = props.getBoolean(SHARED_P, true); connected = props.getBoolean(CACHE_CONNECTED_P, true); debug = props.getBoolean(DEBUG_P, false); // now create the add-on classes validator_c = props.getString(VALIDATOR_P, "org.w3c.www.protocol.http.cache.SimpleCacheValidator"); sweeper_c = props.getString(SWEEPER_P, "org.w3c.www.protocol.http.cache.SimpleCacheSweeper"); serializer_c = props.getString(SERIALIZER_P, "org.w3c.www.protocol.http.cache.SimpleCacheSerializer"); try { Class c; c = Class.forName(validator_c); validator = (CacheValidator) c.newInstance(); validator.initialize(this); c = Class.forName(sweeper_c); sweeper = (CacheSweeper) c.newInstance(); sweeper.initialize(this); c = Class.forName(serializer_c); serializer = (CacheSerializer) c.newInstance(); } catch (Exception ex) { // a fatal error! The cache won't be loaded... ex.printStackTrace(); throw new PropRequestFilterException("Unable to start cache"); } // now create the store as we have the basic things here store = new CacheStore(); try { store.initialize(this); } catch (InvalidCacheException ex) { // hum no worky, should do some action there! if (debug) { ex.printStackTrace(); } } // now start the sweeper sweeper.start(); // Start the ActiveStream handler: ActiveStream.initialize(); // Register for property changes: props.registerObserver(this); // Now, we are ready, register that filter: manager.setFilter(this); }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?