View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.util;
16  
17  import java.util.regex.Matcher;
18  import java.util.regex.Pattern;
19  
20  import org.htmlunit.HttpHeader;
21  import org.htmlunit.WebResponse;
22  
23  /**
24   * @author Anton Demydenko
25   * @author Lai Quang Duong
26   */
27  public final class HeaderUtils {
28  
29      private static final String CACHE_CONTROL_PRIVATE = "private";
30      private static final String CACHE_CONTROL_PUBLIC = "public";
31      private static final String CACHE_CONTROL_NO_STORE = "no-store";
32      private static final String CACHE_CONTROL_NO_CACHE = "no-cache";
33      private static final String CACHE_CONTROL_MAX_AGE = "max-age";
34      private static final String CACHE_CONTROL_S_MAXAGE = "s-maxage";
35      private static final Pattern MAX_AGE_HEADER_PATTERN = Pattern.compile("^.*max-age=(\\d+).*$");
36      private static final Pattern S_MAXAGE_HEADER_PATTERN = Pattern.compile("^.*s-maxage=(\\d+).*$");
37  
38      private HeaderUtils() {
39          // utility class
40      }
41  
42      /**
43       * @param response {@code WebResponse}
44       * @return if 'Cache-Control' header is present and contains 'private' value
45       */
46      public static boolean containsPrivate(final WebResponse response) {
47          return containsCacheControlValue(response, CACHE_CONTROL_PRIVATE);
48      }
49  
50      /**
51       * @param response {@code WebResponse}
52       * @return if 'Cache-Control' header is present and contains 'public' value
53       */
54      public static boolean containsPublic(final WebResponse response) {
55          return containsCacheControlValue(response, CACHE_CONTROL_PUBLIC);
56      }
57  
58      /**
59       * @param response {@code WebResponse}
60       * @return if 'Cache-Control' header is present and contains 'no-store' value
61       */
62      public static boolean containsNoStore(final WebResponse response) {
63          return containsCacheControlValue(response, CACHE_CONTROL_NO_STORE);
64      }
65  
66      /**
67       * @param response {@code WebResponse}
68       * @return if 'Cache-Control' header is present and contains 'no-cache' value@return
69       */
70      public static boolean containsNoCache(final WebResponse response) {
71          return containsCacheControlValue(response, CACHE_CONTROL_NO_CACHE);
72      }
73  
74      /**
75       * @param response {@code WebResponse}
76       * @return if 'Etag' header is present
77       */
78      public static boolean containsETag(final WebResponse response) {
79          return response.getResponseHeaderValue(HttpHeader.ETAG) != null;
80      }
81  
82      /**
83       * @param response {@code WebResponse}
84       * @return if 'Last-Modified' header is present
85       */
86      public static boolean containsLastModified(final WebResponse response) {
87          return response.getResponseHeaderValue(HttpHeader.LAST_MODIFIED) != null;
88      }
89  
90      /**
91       * @param response {@code WebResponse}
92       * @return if 'Cache-Control' header is present and contains 's-maxage' value
93       */
94      public static boolean containsSMaxage(final WebResponse response) {
95          return containsCacheControlValue(response, CACHE_CONTROL_S_MAXAGE);
96      }
97  
98      /**
99       * @param response {@code WebResponse}
100      * @return if 'Cache-Control' header is present and contains 'max-age' value
101      */
102     public static boolean containsMaxAge(final WebResponse response) {
103         return containsCacheControlValue(response, CACHE_CONTROL_MAX_AGE);
104     }
105 
106     /**
107      * @param response {@code WebResponse}
108      * @return if 'Cache-Control' header is present and contains 'max-age' value
109      */
110     public static boolean containsMaxAgeOrSMaxage(final WebResponse response) {
111         final String cacheControl = response.getResponseHeaderValue(HttpHeader.CACHE_CONTROL);
112         if (StringUtils.containsIgnoreCase(cacheControl, CACHE_CONTROL_MAX_AGE)) {
113             return true;
114         }
115         return StringUtils.containsIgnoreCase(cacheControl, CACHE_CONTROL_S_MAXAGE);
116     }
117 
118     /**
119      * @param response {@code WebResponse}
120      * @return value of 's-maxage' directive and 0 if it is absent
121      */
122     public static long sMaxage(final WebResponse response) {
123         if (containsCacheControlValue(response, CACHE_CONTROL_S_MAXAGE)) {
124             return directiveValue(response, S_MAXAGE_HEADER_PATTERN);
125         }
126         return 0;
127     }
128 
129     /**
130      * @param response {@code WebResponse}
131      * @return value of 'max-age' directive and 0 if it is absent
132      */
133     public static long maxAge(final WebResponse response) {
134         if (containsCacheControlValue(response, CACHE_CONTROL_MAX_AGE)) {
135             return directiveValue(response, MAX_AGE_HEADER_PATTERN);
136         }
137 
138         return 0;
139     }
140 
141     private static long directiveValue(final WebResponse response, final Pattern pattern) {
142         final String value = response.getResponseHeaderValue(HttpHeader.CACHE_CONTROL);
143         if (value != null) {
144             final Matcher matcher = pattern.matcher(value);
145             if (matcher.matches()) {
146                 return Long.parseLong(matcher.group(1));
147             }
148         }
149 
150         return 0;
151     }
152 
153     private static boolean containsCacheControlValue(final WebResponse response, final String value) {
154         final String cacheControl = response.getResponseHeaderValue(HttpHeader.CACHE_CONTROL);
155         return StringUtils.containsIgnoreCase(cacheControl, value);
156     }
157 }