Hi,
I created simple class (additionally to existing HttpCacheAction. I am using also simple JavaScript which generates 304 (don't know Cocoon in-depth yet...) The rest: HTTPD uses _few_ multithreaded processes (worker model), and few per-process instances of cache (It was true with v.2.0.44, I tested it 4 years ago). I expect that user may get page from different caches. I set KeepAlive On and problem temporarily disappeared, but need to perform some additional load-stress tests. HTTP Caching works fine now, you may sniff HTTP at http://www.tokenizer.org (expiration: 2 hours, Apache HTTPD, Cocoon 2.1.10, Tomcat 5.5.20, SOLR 1.1) Thanks for responses! JavaScript: =========== function notModified() { cocoon.response.reset(); cocoon.response.setStatus(304,"Not Modified"); cocoon.sendPage("304.txt"); //empty text file } Pipeline: ========= <map:match pattern="**/"> <map:act type="cache304"> <map:call function="main" /> </map:act> <map:call function="notModified"/> </map:match> ......... <map:match pattern="aggregate/*"> <map:act type="cache200" /> <map:aggregate element="aggregate"> <map:part src="cocoon:/path_xml" /> <map:part src="cocoon:/query_xml" /> <map:part src="cocoon:/engine_xml/{1}" /> </map:aggregate> <map:transform src="solr/simple-page2html.xsl" /> <map:serialize type="xhtml" /> </map:match> Java ===== package org.tz; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.avalon.framework.parameters.Parameters; import org.apache.avalon.framework.thread.ThreadSafe; import org.apache.cocoon.acting.AbstractConfigurableAction; import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.Redirector; import org.apache.cocoon.environment.Request; import org.apache.cocoon.environment.SourceResolver; import org.apache.commons.lang.time.DateUtils; import org.apache.commons.lang.time.FastDateFormat; public class HttpCacheAction304 extends AbstractConfigurableAction implements ThreadSafe { public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception { Request request = ObjectModelHelper.getRequest(objectModel); Map values = new HashMap(1); values.put("test", "test"); String ifModifiedSince = request.getHeader("If-Modified-Since"); //System.out.println("ifModifiedSince: "+ifModifiedSince); if (ifModifiedSince == null) { return Collections.unmodifiableMap(values); } else { Calendar expireTime = Calendar.getInstance(DateUtils.UTC_TIME_ZONE); //DateFormat df = DateFormat.getDateInstance(DateFormat.FULL); SimpleDateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy kk:mm:ss zzz"); expireTime.setTime(df.parse(ifModifiedSince)); System.out.println("ifModifiedSince Parsed: "+expireTime.getTime()); expireTime.add(Calendar.DATE, this.days); expireTime.add(Calendar.HOUR, this.hours); expireTime.add(Calendar.MINUTE, this.minutes); expireTime.add(Calendar.SECOND, this.seconds); Calendar currentTime = Calendar .getInstance(DateUtils.UTC_TIME_ZONE); System.out.println("currentTime: "+currentTime.getTime()); System.out.println("expireTime: "+expireTime.getTime()); if (expireTime.getTime().getTime() - currentTime.getTime().getTime() > 0) { return null; } else { return Collections.unmodifiableMap(values); } } } private FastDateFormat formatter = null; int days = 0; int hours = 0; int minutes = 0; int seconds = 0; public void configure(Configuration configuration) throws ConfigurationException { super.configure(configuration); // RFC-822 Date with a GMT based time zone this.formatter = FastDateFormat.getInstance( "EEE, dd MMM yyyy kk:mm:ss zzz", DateUtils.UTC_TIME_ZONE); this.days = configuration.getChild("days").getValueAsInteger(0); this.hours = configuration.getChild("hours").getValueAsInteger(0); this.minutes = configuration.getChild("minutes").getValueAsInteger(0); this.seconds = configuration.getChild("seconds").getValueAsInteger(0); } }
