mirror of
https://github.com/apache/lucene.git
synced 2025-02-28 21:39:25 +00:00
SOLR-505 Give RequestHandlers the possiblity to suppress the generation of HTTP caching headers
git-svn-id: https://svn.apache.org/repos/asf/lucene/solr/trunk@659657 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
a0de6f7b9f
commit
5ba95af1bb
@ -79,6 +79,7 @@ public class MoreLikeThisHandler extends RequestHandlerBase
|
||||
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception
|
||||
{
|
||||
RequestHandlerUtils.addExperimentalFormatWarning( rsp );
|
||||
rsp.setHttpCaching(true);
|
||||
|
||||
SolrParams params = req.getParams();
|
||||
SolrIndexSearcher searcher = req.getSearcher();
|
||||
|
@ -263,6 +263,7 @@ public class SpellCheckerRequestHandler extends RequestHandlerBase implements So
|
||||
@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");
|
||||
|
@ -126,6 +126,8 @@ public class SearchHandler extends RequestHandlerBase implements SolrCoreAware
|
||||
|
||||
final RTimer timer = rb.isDebug() ? new RTimer() : null;
|
||||
|
||||
rsp.setHttpCaching(true);
|
||||
|
||||
if (timer == null) {
|
||||
// non-debugging prepare phase
|
||||
for( SearchComponent c : components ) {
|
||||
|
@ -72,6 +72,11 @@ public class SolrQueryResponse {
|
||||
// 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 class SolrQueryResponse {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ public class CacheHeaderTest extends CacheHeaderTestBase {
|
||||
|
||||
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 @@ public class CacheHeaderTest extends CacheHeaderTestBase {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +93,20 @@ public abstract class CacheHeaderTestBase extends SolrExampleTestBase {
|
||||
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();
|
||||
}
|
||||
|
@ -258,13 +258,11 @@ public class SolrDispatchFilter implements Filter
|
||||
}
|
||||
|
||||
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 @@ public class SolrDispatchFilter implements Filter
|
||||
* 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 @@ public class SolrDispatchFilter implements Filter
|
||||
// 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);
|
||||
|
@ -35,6 +35,7 @@ import org.apache.solr.common.SolrException;
|
||||
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 @@ public final class HttpCacheHeaderUtil {
|
||||
/**
|
||||
* 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 final class HttpCacheHeaderUtil {
|
||||
*/
|
||||
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 @@ public final class HttpCacheHeaderUtil {
|
||||
}
|
||||
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())+'"');
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user