You are viewing a plain text version of this content. The canonical link for it is here.
Posted to solr-commits@lucene.apache.org by ot...@apache.org on 2008/05/23 22:55:48 UTC
svn commit: r659657 - in /lucene/solr/trunk/src:
java/org/apache/solr/handler/ java/org/apache/solr/handler/component/
java/org/apache/solr/request/ test/org/apache/solr/servlet/
webapp/src/org/apache/solr/servlet/ webapp/src/org/apache/solr/servlet/ca...
Author: otis
Date: Fri May 23 13:55:48 2008
New Revision: 659657
URL: http://svn.apache.org/viewvc?rev=659657&view=rev
Log:
SOLR-505 Give RequestHandlers the possiblity to suppress the generation of HTTP caching headers
Modified:
lucene/solr/trunk/src/java/org/apache/solr/handler/MoreLikeThisHandler.java
lucene/solr/trunk/src/java/org/apache/solr/handler/SpellCheckerRequestHandler.java
lucene/solr/trunk/src/java/org/apache/solr/handler/component/SearchHandler.java
lucene/solr/trunk/src/java/org/apache/solr/request/SolrQueryResponse.java
lucene/solr/trunk/src/test/org/apache/solr/servlet/CacheHeaderTest.java
lucene/solr/trunk/src/test/org/apache/solr/servlet/CacheHeaderTestBase.java
lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java
lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/cache/HttpCacheHeaderUtil.java
lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/cache/Method.java
Modified: lucene/solr/trunk/src/java/org/apache/solr/handler/MoreLikeThisHandler.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/handler/MoreLikeThisHandler.java?rev=659657&r1=659656&r2=659657&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/handler/MoreLikeThisHandler.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/handler/MoreLikeThisHandler.java Fri May 23 13:55:48 2008
@@ -79,6 +79,7 @@
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception
{
RequestHandlerUtils.addExperimentalFormatWarning( rsp );
+ rsp.setHttpCaching(true);
SolrParams params = req.getParams();
SolrIndexSearcher searcher = req.getSearcher();
Modified: lucene/solr/trunk/src/java/org/apache/solr/handler/SpellCheckerRequestHandler.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/handler/SpellCheckerRequestHandler.java?rev=659657&r1=659656&r2=659657&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/handler/SpellCheckerRequestHandler.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/handler/SpellCheckerRequestHandler.java Fri May 23 13:55:48 2008
@@ -263,6 +263,7 @@
@Override
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp)
throws Exception {
+ rsp.setHttpCaching(true);
SolrParams p = req.getParams();
String words = p.get("q");
String cmd = p.get("cmd");
Modified: lucene/solr/trunk/src/java/org/apache/solr/handler/component/SearchHandler.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/handler/component/SearchHandler.java?rev=659657&r1=659656&r2=659657&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/handler/component/SearchHandler.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/handler/component/SearchHandler.java Fri May 23 13:55:48 2008
@@ -126,6 +126,8 @@
final RTimer timer = rb.isDebug() ? new RTimer() : null;
+ rsp.setHttpCaching(true);
+
if (timer == null) {
// non-debugging prepare phase
for( SearchComponent c : components ) {
Modified: lucene/solr/trunk/src/java/org/apache/solr/request/SolrQueryResponse.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/request/SolrQueryResponse.java?rev=659657&r1=659656&r2=659657&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/request/SolrQueryResponse.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/request/SolrQueryResponse.java Fri May 23 13:55:48 2008
@@ -72,6 +72,11 @@
// error if this is set...
protected Exception err;
+ /**
+ * Should this response be tagged with HTTP caching headers?
+ */
+ protected boolean httpCaching=false;
+
/***
// another way of returning an error
int errCode;
@@ -199,5 +204,20 @@
public NamedList getToLog() {
return toLog;
}
-
+
+ /**
+ * Enables or disables the emission of HTTP caching headers for this response.
+ * @param httpCaching true=emit caching headers, false otherwise
+ */
+ public void setHttpCaching(boolean httpCaching) {
+ this.httpCaching=httpCaching;
+ }
+
+ /**
+ * Should this response emit HTTP caching headers?
+ * @return true=yes emit headers, false otherwise
+ */
+ public boolean isHttpCaching() {
+ return this.httpCaching;
+ }
}
Modified: lucene/solr/trunk/src/test/org/apache/solr/servlet/CacheHeaderTest.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/org/apache/solr/servlet/CacheHeaderTest.java?rev=659657&r1=659656&r2=659657&view=diff
==============================================================================
--- lucene/solr/trunk/src/test/org/apache/solr/servlet/CacheHeaderTest.java (original)
+++ lucene/solr/trunk/src/test/org/apache/solr/servlet/CacheHeaderTest.java Fri May 23 13:55:48 2008
@@ -16,18 +16,68 @@
*/
package org.apache.solr.servlet;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
import java.util.Date;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpMethodBase;
+import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.util.DateUtil;
/**
* A test case for the several HTTP cache headers emitted by Solr
*/
public class CacheHeaderTest extends CacheHeaderTestBase {
- @Override public String getSolrConfigFilename() { return "solrconfig.xml"; }
+ @Override
+ public String getSolrConfigFilename() {
+ return "solrconfig.xml";
+ }
+
+ protected static final String FILENAME = "cacheheadertest.csv";
+
+ protected static final String CHARSET = "UTF-8";
+
+ protected static final String CONTENTS = "id\n100\n101\n102";
+
+ public void testCacheVetoHandler() throws Exception {
+ File f=makeFile(CONTENTS);
+ HttpMethodBase m=getUpdateMethod("GET");
+ m.setQueryString(new NameValuePair[] { new NameValuePair("stream.file",f.getCanonicalPath())});
+ getClient().executeMethod(m);
+ assertEquals(200, m.getStatusCode());
+ checkVetoHeaders(m);
+ }
+ public void testCacheVetoException() throws Exception {
+ HttpMethodBase m = getSelectMethod("GET");
+ // We force an exception from Solr. This should emit "no-cache" HTTP headers
+ m.setQueryString(new NameValuePair[] { new NameValuePair("q", "xyz:solr"),
+ new NameValuePair("qt", "standard") });
+ getClient().executeMethod(m);
+ assertFalse(m.getStatusCode() == 200);
+ checkVetoHeaders(m);
+ }
+
+ protected void checkVetoHeaders(HttpMethodBase m) throws Exception {
+ Header head = m.getResponseHeader("Cache-Control");
+ assertNotNull("We got no Cache-Control header", head);
+ assertEquals("no-cache, no-store", head.getValue());
+
+ head = m.getResponseHeader("Pragma");
+ assertNotNull("We got no Pragma header", head);
+ assertEquals("no-cache", head.getValue());
+
+ head = m.getResponseHeader("Expires");
+ assertNotNull("We got no Expires header", head);
+ Date d = DateUtil.parseDate(head.getValue());
+ assertTrue("We got no Expires header far in the past", System
+ .currentTimeMillis()
+ - d.getTime() > 100000);
+ }
+
protected void doLastModified(String method) throws Exception {
// We do a first request to get the last modified
// This must result in a 200 OK response
@@ -162,8 +212,8 @@
Header head = m.getResponseHeader("Cache-Control");
assertNull("We got a cache-control header in response to POST", head);
-
- head=m.getResponseHeader("Expires");
+
+ head = m.getResponseHeader("Expires");
assertNull("We got an Expires header in response to POST", head);
} else {
HttpMethodBase m = getSelectMethod(method);
@@ -172,9 +222,26 @@
Header head = m.getResponseHeader("Cache-Control");
assertNotNull("We got no cache-control header", head);
-
- head=m.getResponseHeader("Expires");
- assertNotNull("We got no Expires header in response",head);
+
+ head = m.getResponseHeader("Expires");
+ assertNotNull("We got no Expires header in response", head);
+ }
+ }
+
+ protected File makeFile(String contents) {
+ return makeFile(contents, CHARSET);
+ }
+
+ protected File makeFile(String contents, String charset) {
+ try {
+ File f=new File(FILENAME);
+ Writer out = new OutputStreamWriter(new FileOutputStream(f),
+ charset);
+ out.write(contents);
+ out.close();
+ return f;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
}
}
}
Modified: lucene/solr/trunk/src/test/org/apache/solr/servlet/CacheHeaderTestBase.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/org/apache/solr/servlet/CacheHeaderTestBase.java?rev=659657&r1=659656&r2=659657&view=diff
==============================================================================
--- lucene/solr/trunk/src/test/org/apache/solr/servlet/CacheHeaderTestBase.java (original)
+++ lucene/solr/trunk/src/test/org/apache/solr/servlet/CacheHeaderTestBase.java Fri May 23 13:55:48 2008
@@ -93,6 +93,20 @@
return m;
}
+ protected HttpMethodBase getUpdateMethod(String method) {
+ HttpMethodBase m = null;
+
+ if ("GET".equals(method)) {
+ m=new GetMethod(server.getBaseURL()+"/update/csv");
+ } else if ("POST".equals(method)) {
+ m=new PostMethod(server.getBaseURL()+"/update/csv");
+ } else if ("HEAD".equals(method)) {
+ m=new HeadMethod(server.getBaseURL()+"/update/csv");
+ }
+
+ return m;
+ }
+
protected HttpClient getClient() {
return server.getHttpClient();
}
Modified: lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java?rev=659657&r1=659656&r2=659657&view=diff
==============================================================================
--- lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java (original)
+++ lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java Fri May 23 13:55:48 2008
@@ -258,13 +258,11 @@
}
final Method reqMethod = Method.getMethod(req.getMethod());
- if (Method.POST != reqMethod) {
- HttpCacheHeaderUtil.setCacheControlHeader(config, resp);
- }
+ HttpCacheHeaderUtil.setCacheControlHeader(config, resp, reqMethod);
// unless we have been explicitly told not to, do cache validation
// if we fail cache validation, execute the query
if (config.getHttpCachingConfig().isNever304() ||
- !HttpCacheHeaderUtil.doCacheHeaderValidation(solrReq, req, resp)) {
+ !HttpCacheHeaderUtil.doCacheHeaderValidation(solrReq, req, reqMethod, resp)) {
SolrQueryResponse solrRsp = new SolrQueryResponse();
/* even for HEAD requests, we need to execute the handler to
* ensure we don't get an error (and to make sure the correct
@@ -272,6 +270,7 @@
* Content-Type)
*/
this.execute( req, handler, solrReq, solrRsp );
+ HttpCacheHeaderUtil.checkHttpCachingVeto(solrRsp, resp, reqMethod);
// add info to http headers
//TODO: See SOLR-232 and SOLR-267.
/*try {
@@ -289,7 +288,7 @@
// Now write it out
QueryResponseWriter responseWriter = core.getQueryResponseWriter(solrReq);
response.setContentType(responseWriter.getContentType(solrReq, solrRsp));
- if (Method.HEAD != Method.getMethod(req.getMethod())) {
+ if (Method.HEAD != reqMethod) {
if (responseWriter instanceof BinaryQueryResponseWriter) {
BinaryQueryResponseWriter binWriter = (BinaryQueryResponseWriter) responseWriter;
binWriter.write(response.getOutputStream(), solrReq, solrRsp);
Modified: lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/cache/HttpCacheHeaderUtil.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/cache/HttpCacheHeaderUtil.java?rev=659657&r1=659656&r2=659657&view=diff
==============================================================================
--- lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/cache/HttpCacheHeaderUtil.java (original)
+++ lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/cache/HttpCacheHeaderUtil.java Fri May 23 13:55:48 2008
@@ -35,6 +35,7 @@
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.request.SolrQueryResponse;
import org.apache.solr.request.SolrRequestHandler;
import org.apache.commons.codec.binary.Base64;
@@ -167,10 +168,16 @@
/**
* Set the Cache-Control HTTP header (and Expires if needed)
* based on the SolrConfig.
+ * @param conf The config of the SolrCore handling this request
+ * @param resp The servlet response object to modify
+ * @param method The request method (GET, POST, ...) used by this request
*/
public static void setCacheControlHeader(final SolrConfig conf,
- final HttpServletResponse resp) {
-
+ final HttpServletResponse resp, final Method method) {
+ // We do not emit HTTP header for POST and OTHER request types
+ if (Method.POST==method || Method.OTHER==method) {
+ return;
+ }
final String cc = conf.getHttpCachingConfig().getCacheControlHeader();
if (null != cc) {
resp.setHeader("Cache-Control", cc);
@@ -202,10 +209,13 @@
*/
public static boolean doCacheHeaderValidation(final SolrQueryRequest solrReq,
final HttpServletRequest req,
+ final Method reqMethod,
final HttpServletResponse resp)
throws IOException {
-
- final Method reqMethod=Method.getMethod(req.getMethod());
+
+ if (Method.POST==reqMethod || Method.OTHER==reqMethod) {
+ return false;
+ }
final long lastMod = HttpCacheHeaderUtil.calcLastModified(solrReq);
final String etag = HttpCacheHeaderUtil.calcEtag(solrReq);
@@ -295,4 +305,42 @@
}
return false;
}
+
+ /**
+ * Checks if the downstream request handler wants to avoid HTTP caching of
+ * the response.
+ *
+ * @param solrRsp The Solr response object
+ * @param resp The HTTP servlet response object
+ * @param reqMethod The HTTP request type
+ */
+ public static void checkHttpCachingVeto(final SolrQueryResponse solrRsp,
+ HttpServletResponse resp, final Method reqMethod) {
+ // For POST we do nothing. They never get cached
+ if (Method.POST == reqMethod || Method.OTHER == reqMethod) {
+ return;
+ }
+ // If the request handler has not vetoed and there is no
+ // exception silently return
+ if (solrRsp.isHttpCaching() && solrRsp.getException() == null) {
+ return;
+ }
+
+ // Otherwise we tell the caches that we don't want to cache the response
+ resp.setHeader("Cache-Control", "no-cache, no-store");
+
+ // For HTTP/1.0 proxy caches
+ resp.setHeader("Pragma", "no-cache");
+
+ // This sets the expiry date to a date in the past
+ // As long as no time machines get invented this is safe
+ resp.setHeader("Expires", "Sat, 01 Jan 2000 01:00:00 GMT");
+
+ // We signal "just modified" just in case some broken
+ // proxy cache does not follow the above headers
+ resp.setDateHeader("Last-Modified", System.currentTimeMillis());
+
+ // We override the ETag with something different
+ resp.setHeader("ETag", '"'+Long.toHexString(System.currentTimeMillis())+'"');
+ }
}
Modified: lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/cache/Method.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/cache/Method.java?rev=659657&r1=659656&r2=659657&view=diff
==============================================================================
--- lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/cache/Method.java (original)
+++ lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/cache/Method.java Fri May 23 13:55:48 2008
@@ -18,24 +18,13 @@
package org.apache.solr.servlet.cache;
public enum Method {
- GET("GET"), POST("POST"), HEAD("HEAD"), OTHER("");
-
- private final String method;
-
- Method(String method) {
- this.method = method.intern();
- }
+ GET, POST, HEAD, OTHER;
public static Method getMethod(String method) {
- method = method.toUpperCase().intern();
-
- for (Method m : Method.values()) {
- // we can use == because we interned the String objects
- if (m.method==method) {
- return m;
- }
+ try {
+ return Method.valueOf(method.toUpperCase());
+ } catch (Exception e) {
+ return OTHER;
}
-
- return OTHER;
}
}