Program: 30166
Project: 30166
Buggy source:
/** 
 * The <code>doFilter</code> method of the Filter is called by the container each time a request/response pair is passed through the chain due to a client request for a resource at the end of the chain. The FilterChain passed in to this method allows the Filter to pass on the request and response to the next entity in the chain.
 * @param srequest the runtime request
 * @param sresponse the runtime response
 * @param chain the filter chain to in the request processing
 * @throws IOException , ServletException - First check if this HTTP method permits caching (using helper)  if not, call the downstream filter and return.  - Otherwise, get the key based on the request (using helper).  - Check if we have a response entry in the cache already.  - If there is entry and is valid, write out the response from that entry.  - create a CachingResponse and CachingOutputStream wrappers and call  the downstream filter
 */
public void doFilter(ServletRequest srequest,ServletResponse sresponse,FilterChain chain) throws IOException, ServletException {
  String key;
  HttpServletRequest request=(HttpServletRequest)srequest;
  HttpServletResponse response=(HttpServletResponse)sresponse;
  request.setAttribute(DefaultCacheHelper.ATTR_CACHING_FILTER_NAME,filterName);
  request.setAttribute(CacheHelper.ATTR_CACHE_MAPPED_SERVLET_NAME,servletName);
  request.setAttribute(CacheHelper.ATTR_CACHE_MAPPED_URL_PATTERN,urlPattern);
  boolean isFine=_logger.isLoggable(Level.FINE);
  if (isEnabled && helper.isCacheable((HttpServletRequest)request) && (key=helper.getCacheKey(request)) != null) {
    int index=cache.getIndex(key);
    if (isFine) {
      _logger.fine("String_Node_Str" + request.getServletPath() + "String_Node_Str"+ key+ "String_Node_Str"+ index);
    }
    HttpCacheEntry entry=null;
    boolean entryReady=false, waitForRefresh=true;
    if (!helper.isRefreshNeeded(request)) {
      do {
        entry=(HttpCacheEntry)cache.get(key);
        if (entry != null && entry.isValid()) {
          entryReady=true;
          break;
        }
 else {
          waitForRefresh=cache.waitRefresh(index);
        }
      }
 while (waitForRefresh);
    }
 else {
      if (isFine) {
        _logger.fine("String_Node_Str" + request.getServletPath() + "String_Node_Str"+ key);
      }
    }
    if (entryReady) {
      if (isFine) {
        _logger.fine("String_Node_Str" + request.getServletPath() + "String_Node_Str"+ key);
      }
      sendCachedResponse(entry,response);
    }
 else {
      CachingResponseWrapper wrapper=null;
      boolean needNotify=true;
      try {
        wrapper=new CachingResponseWrapper(response);
        chain.doFilter(srequest,(ServletResponse)wrapper);
        if (!wrapper.isError()) {
          int timeout=helper.getTimeout(request);
          entry=wrapper.cacheResponse();
          if (timeout == CacheHelper.TIMEOUT_VALUE_NOT_SET) {
            Long lval=wrapper.getExpiresDateHeader();
            if (lval == null) {
              timeout=manager.getDefaultTimeout();
              entry.computeExpireTime(timeout);
            }
 else {
              long expireTime=lval.longValue();
              entry.setExpireTime(expireTime);
            }
          }
 else {
            entry.computeExpireTime(timeout);
          }
          cache.put(key,entry,entry.getSize());
          cache.notifyRefresh(index);
          needNotify=false;
          writeBody(entry,response);
        }
 else {
          cache.remove(key);
        }
      }
  finally {
        if (needNotify) {
          cache.notifyRefresh(index);
        }
        if (wrapper != null) {
          wrapper.clear();
        }
      }
    }
  }
 else {
    if (isFine) {
      _logger.fine("String_Node_Str" + request.getServletPath() + "String_Node_Str"+ isEnabled);
    }
    request.removeAttribute(DefaultCacheHelper.ATTR_CACHING_FILTER_NAME);
    request.removeAttribute(CacheHelper.ATTR_CACHE_MAPPED_SERVLET_NAME);
    request.removeAttribute(CacheHelper.ATTR_CACHE_MAPPED_URL_PATTERN);
    chain.doFilter(srequest,sresponse);
  }
}

Fixed version (ground truth):
/** 
 * The <code>doFilter</code> method of the Filter is called by the container each time a request/response pair is passed through the chain due to a client request for a resource at the end of the chain. The FilterChain passed in to this method allows the Filter to pass on the request and response to the next entity in the chain.
 * @param srequest the runtime request
 * @param sresponse the runtime response
 * @param chain the filter chain to in the request processing
 * @throws IOException , ServletException - First check if this HTTP method permits caching (using helper)  if not, call the downstream filter and return.  - Otherwise, get the key based on the request (using helper).  - Check if we have a response entry in the cache already.  - If there is entry and is valid, write out the response from that entry.  - create a CachingResponse and CachingOutputStream wrappers and call  the downstream filter
 */
public void doFilter(ServletRequest srequest,ServletResponse sresponse,FilterChain chain) throws IOException, ServletException {
  String key;
  HttpServletRequest request=(HttpServletRequest)srequest;
  HttpServletResponse response=(HttpServletResponse)sresponse;
  request.setAttribute(DefaultCacheHelper.ATTR_CACHING_FILTER_NAME,filterName);
  request.setAttribute(CacheHelper.ATTR_CACHE_MAPPED_SERVLET_NAME,servletName);
  request.setAttribute(CacheHelper.ATTR_CACHE_MAPPED_URL_PATTERN,urlPattern);
  boolean isFine=_logger.isLoggable(Level.FINE);
  if (isEnabled && helper.isCacheable((HttpServletRequest)request) && (key=helper.getCacheKey(request)) != null) {
    int index=cache.getIndex(key);
    if (isFine) {
      _logger.fine("String_Node_Str" + request.getServletPath() + "String_Node_Str"+ key+ "String_Node_Str"+ index);
    }
    HttpCacheEntry entry=null;
    boolean entryReady=false, waitForRefresh=true;
    if (!helper.isRefreshNeeded(request)) {
      do {
        entry=(HttpCacheEntry)cache.get(key);
        if (entry != null && entry.isValid()) {
          entryReady=true;
          break;
        }
 else {
          waitForRefresh=waitForRefresh(request,key,index);
        }
      }
 while (waitForRefresh);
    }
 else {
      if (isFine) {
        _logger.fine("String_Node_Str" + request.getServletPath() + "String_Node_Str"+ key);
      }
    }
    if (entryReady) {
      if (isFine) {
        _logger.fine("String_Node_Str" + request.getServletPath() + "String_Node_Str"+ key);
      }
      sendCachedResponse(entry,response);
    }
 else {
      CachingResponseWrapper wrapper=null;
      boolean needNotify=true;
      try {
        wrapper=new CachingResponseWrapper(response);
        chain.doFilter(srequest,(ServletResponse)wrapper);
        if (!wrapper.isError()) {
          int timeout=helper.getTimeout(request);
          entry=wrapper.cacheResponse();
          if (timeout == CacheHelper.TIMEOUT_VALUE_NOT_SET) {
            Long lval=wrapper.getExpiresDateHeader();
            if (lval == null) {
              timeout=manager.getDefaultTimeout();
              entry.computeExpireTime(timeout);
            }
 else {
              long expireTime=lval.longValue();
              entry.setExpireTime(expireTime);
            }
          }
 else {
            entry.computeExpireTime(timeout);
          }
          cache.put(key,entry,entry.getSize());
          cache.notifyRefresh(index);
          needNotify=false;
          writeBody(entry,response);
        }
 else {
          cache.remove(key);
        }
      }
  finally {
        if (needNotify) {
          cache.notifyRefresh(index);
        }
        if (wrapper != null) {
          wrapper.clear();
        }
      }
    }
  }
 else {
    if (isFine) {
      _logger.fine("String_Node_Str" + request.getServletPath() + "String_Node_Str"+ isEnabled);
    }
    request.removeAttribute(DefaultCacheHelper.ATTR_CACHING_FILTER_NAME);
    request.removeAttribute(CacheHelper.ATTR_CACHE_MAPPED_SERVLET_NAME);
    request.removeAttribute(CacheHelper.ATTR_CACHE_MAPPED_URL_PATTERN);
    chain.doFilter(srequest,sresponse);
  }
}