aboutsummaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/search/searchers/CacheControlSearcher.java
blob: 8f6b619d77c9a2a4811c99d3886517e83c4147e9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.searchers;

import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
import com.yahoo.processing.request.CompoundName;
import com.yahoo.search.searchchain.Execution;

/**
 * Searcher that sets cache control HTTP headers in response based on query/GET parameters to
 * control caching done by proxy/caches such as YSquid and YTS:
 * <ul>
 *    <li>max-age=XXX - set with &amp;cachecontrol.maxage parameter
 *    <li>stale-while-revalidate=YYY - set with &amp;cachecontrol.staleage
 *    <li>no-cache - if Vespa &amp;noCache or &amp;cachecontrol.nocache parameter is set to true
 * </ul>
 *
 * <p>This is controlled through the three query parameters <code>cachecontrol.maxage</code>,
 * <code>cachecontrol.staleage</code> and <code>cachecontrol.nocache</code>, with the obvious meanings.</p>
 *
 * Example:
 * <ul>
 *    <li>Request: "?query=foo&amp;cachecontrol.maxage=60&amp;cachecontrol.staleage=3600"
 *    <li>Response HTTP header: "Cache-Control: max-age=60, revalidate-while-stale=3600"
 * </ul>
 *
 * Further documentation on use of Cache-Control headers:
 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
 *
 * @author Frode Lundgren
 */
public class CacheControlSearcher extends Searcher {

    private static final CompoundName cachecontrolNocache=CompoundName.from("cachecontrol.nocache");
    private static final CompoundName cachecontrolMaxage=CompoundName.from("cachecontrol.maxage");
    private static final CompoundName cachecontrolStaleage=CompoundName.from("cachecontrol.staleage");

    public static final String CACHE_CONTROL_HEADER = "Cache-Control";

    @Override
    public Result search(Query query, Execution execution) {
        query.trace("CacheControlSearcher: Running version $Revision$", false, 6);
        Result result = execution.search(query);
        query = result.getQuery();

        if (result.getHeaders(true) == null) {
            query.trace("CacheControlSearcher: No HTTP header map available - skipping searcher.", false, 5);
            return result;
        }

        // If you specify no-cache, no further cache control headers make sense
        if (query.properties().getBoolean(cachecontrolNocache, false) || query.getNoCache()) {
            result.getHeaders(true).put(CACHE_CONTROL_HEADER, "no-cache");
            query.trace("CacheControlSearcher: Added no-cache header", false, 4);
            return result;
        }

        // Handle max-age header
        int maxage = query.properties().getInteger(cachecontrolMaxage, -1);
        if (maxage > 0) {
            result.getHeaders(true).put(CACHE_CONTROL_HEADER, "max-age=" + maxage);
            query.trace("CacheControlSearcher: Set max-age header to " + maxage, false, 4);
        }

        // Handle stale-while-revalidate header
        int staleage = query.properties().getInteger(cachecontrolStaleage, -1);
        if (staleage > 0) {
            result.getHeaders(true).put(CACHE_CONTROL_HEADER, "stale-while-revalidate=" + staleage);
            query.trace("CacheControlSearcher: Set stale-while-revalidate header to " + staleage, false, 4);
        }

        return result;
    }
}