View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.hc.client5.http.impl.cache;
28  
29  import static org.junit.jupiter.api.Assertions.assertAll;
30  import static org.junit.jupiter.api.Assertions.assertEquals;
31  import static org.junit.jupiter.api.Assertions.assertThrows;
32  import static org.junit.jupiter.api.Assertions.assertTrue;
33  
34  import java.util.Arrays;
35  import java.util.Collections;
36  
37  import org.apache.hc.client5.http.cache.RequestCacheControl;
38  import org.apache.hc.client5.http.cache.ResponseCacheControl;
39  import org.apache.hc.core5.http.Header;
40  import org.apache.hc.core5.http.message.BasicHeader;
41  import org.junit.jupiter.api.Test;
42  
43  public class CacheControlParserTest {
44  
45      private final CacheControlHeaderParser parser = CacheControlHeaderParser.INSTANCE;
46  
47      @Test
48      public void testParseMaxAgeZero() {
49          final Header header = new BasicHeader("Cache-Control", "max-age=0 , this = stuff;");
50          final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
51          assertEquals(0L, cacheControl.getMaxAge());
52      }
53  
54      @Test
55      public void testParseSMaxAge() {
56          final Header header = new BasicHeader("Cache-Control", "s-maxage=3600");
57          final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
58          assertEquals(3600L, cacheControl.getSharedMaxAge());
59      }
60  
61      @Test
62      public void testParseInvalidCacheValue() {
63          final Header header = new BasicHeader("Cache-Control", "max-age=invalid");
64          final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
65          assertEquals(0L, cacheControl.getMaxAge());
66      }
67  
68      @Test
69      public void testParseInvalidHeader() {
70          final Header header = new BasicHeader("Cache-Control", "max-age");
71          final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
72          assertEquals(-1L, cacheControl.getMaxAge());
73      }
74  
75      @Test
76      public void testParseNullHeader() {
77          final Header header = null;
78          assertThrows(NullPointerException.class, () -> parser.parseResponse(Collections.singletonList(header).iterator()));
79      }
80  
81      @Test
82      public void testParseEmptyHeader() {
83          final Header header = new BasicHeader("Cache-Control", "");
84          final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
85          assertEquals(-1L, cacheControl.getMaxAge());
86      }
87  
88      @Test
89      public void testParseCookieEmptyValue() {
90          final Header header = new BasicHeader("Cache-Control", "max-age=,");
91          final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
92          assertEquals(-1L, cacheControl.getMaxAge());
93      }
94  
95      @Test
96      public void testParseNoCache() {
97          final Header header = new BasicHeader(" Cache-Control", "no-cache");
98          final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
99          assertEquals(-1L, cacheControl.getMaxAge());
100     }
101 
102     @Test
103     public void testParseNoDirective() {
104         final Header header = new BasicHeader(" Cache-Control", "");
105         final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
106         assertEquals(-1L, cacheControl.getMaxAge());
107     }
108 
109     @Test
110     public void testGarbage() {
111         final Header header = new BasicHeader("Cache-Control", ",,= blah,");
112         final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
113         assertEquals(-1L, cacheControl.getMaxAge());
114     }
115 
116 
117     @Test
118     public void testParseMultipleDirectives() {
119         final Header header = new BasicHeader("Cache-Control", "max-age=604800, stale-while-revalidate=86400, s-maxage=3600, must-revalidate, private");
120         final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
121 
122         assertAll("Must all pass",
123                 () -> assertEquals(604800L, cacheControl.getMaxAge()),
124                 () -> assertEquals(3600L, cacheControl.getSharedMaxAge()),
125                 () -> assertTrue(cacheControl.isMustRevalidate()),
126                 () -> assertTrue(cacheControl.isCachePrivate())
127         );
128     }
129 
130     @Test
131     public void testParseMultipleDirectives2() {
132         final Header header = new BasicHeader("Cache-Control", "max-age=604800, stale-while-revalidate=86400, must-revalidate, private, s-maxage=3600");
133         final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
134 
135         assertAll("Must all pass",
136                 () -> assertEquals(604800L, cacheControl.getMaxAge()),
137                 () -> assertEquals(3600L, cacheControl.getSharedMaxAge()),
138                 () -> assertTrue(cacheControl.isMustRevalidate()),
139                 () -> assertTrue(cacheControl.isCachePrivate())
140         );
141     }
142 
143     @Test
144     public void testParsePublic() {
145         final Header header = new BasicHeader("Cache-Control", "public");
146         final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
147 
148         assertTrue(cacheControl.isPublic());
149     }
150 
151     @Test
152     public void testParsePrivate() {
153         final Header header = new BasicHeader("Cache-Control", "private");
154         final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
155 
156         assertTrue(cacheControl.isCachePrivate());
157     }
158 
159     @Test
160     public void testParseNoStore() {
161         final Header header = new BasicHeader("Cache-Control", "no-store");
162         final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
163 
164         assertTrue(cacheControl.isNoStore());
165     }
166 
167     @Test
168     public void testParseStaleWhileRevalidate() {
169         final Header header = new BasicHeader("Cache-Control", "max-age=3600, stale-while-revalidate=120");
170         final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
171 
172         assertEquals(120, cacheControl.getStaleWhileRevalidate());
173     }
174 
175     @Test
176     public void testParseNoCacheFields() {
177         final Header header = new BasicHeader("Cache-Control", "no-cache=\"Set-Cookie, Content-Language\", stale-while-revalidate=120");
178         final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
179 
180         assertTrue(cacheControl.isNoCache());
181         assertEquals(2, cacheControl.getNoCacheFields().size());
182         assertTrue(cacheControl.getNoCacheFields().contains("Set-Cookie"));
183         assertTrue(cacheControl.getNoCacheFields().contains("Content-Language"));
184         assertEquals(120, cacheControl.getStaleWhileRevalidate());
185     }
186 
187     @Test
188     public void testParseNoCacheFieldsNoQuote() {
189         final Header header = new BasicHeader("Cache-Control", "no-cache=Set-Cookie, Content-Language, stale-while-revalidate=120");
190         final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
191 
192         assertTrue(cacheControl.isNoCache());
193         assertEquals(1, cacheControl.getNoCacheFields().size());
194         assertTrue(cacheControl.getNoCacheFields().contains("Set-Cookie"));
195         assertEquals(120, cacheControl.getStaleWhileRevalidate());
196     }
197 
198     @Test
199     public void testParseNoCacheFieldsMessy() {
200         final Header header = new BasicHeader("Cache-Control", "no-cache=\"  , , ,,, Set-Cookie  , , Content-Language ,   \", stale-while-revalidate=120");
201         final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
202 
203         assertTrue(cacheControl.isNoCache());
204         assertEquals(2, cacheControl.getNoCacheFields().size());
205         assertTrue(cacheControl.getNoCacheFields().contains("Set-Cookie"));
206         assertTrue(cacheControl.getNoCacheFields().contains("Content-Language"));
207         assertEquals(120, cacheControl.getStaleWhileRevalidate());
208     }
209 
210 
211     @Test
212     public void testParseMultipleHeaders() {
213         // Create headers
214         final Header header1 = new BasicHeader("Cache-Control", "max-age=3600, no-store");
215         final Header header2 = new BasicHeader("Cache-Control", "private, must-revalidate");
216         final Header header3 = new BasicHeader("Cache-Control", "max-age=3600");
217         final Header header4 = new BasicHeader("Cache-Control", "no-store");
218         final Header header5 = new BasicHeader("Cache-Control", "private");
219         final Header header6 = new BasicHeader("Cache-Control", "must-revalidate");
220 
221         // Parse headers
222         final ResponseCacheControl cacheControl1 = parser.parseResponse(Arrays.asList(header1, header2).iterator());
223         final ResponseCacheControl cacheControl2 = parser.parseResponse(Arrays.asList(header3, header4, header5, header6).iterator());
224 
225         // Validate Cache-Control directives
226         assertEquals(cacheControl1.getMaxAge(), cacheControl2.getMaxAge());
227         assertEquals(cacheControl1.isNoStore(), cacheControl2.isNoStore());
228         assertEquals(cacheControl1.isCachePrivate(), cacheControl2.isCachePrivate());
229         assertEquals(cacheControl1.isMustRevalidate(), cacheControl2.isMustRevalidate());
230     }
231 
232     @Test
233     public void testParseRequestMultipleDirectives() {
234         final Header header = new BasicHeader("Cache-Control", "blah, max-age=1111, max-stale=2222, " +
235                 "min-fresh=3333, no-cache, no-store, no-cache, no-stuff, only-if-cached, only-if-cached-or-maybe-not");
236         final RequestCacheControl cacheControl = parser.parseRequest(Collections.singletonList(header).iterator());
237 
238         assertAll("Must all pass",
239                 () -> assertEquals(1111L, cacheControl.getMaxAge()),
240                 () -> assertEquals(2222L, cacheControl.getMaxStale()),
241                 () -> assertEquals(3333L, cacheControl.getMinFresh()),
242                 () -> assertTrue(cacheControl.isNoCache()),
243                 () -> assertTrue(cacheControl.isNoCache()),
244                 () -> assertTrue(cacheControl.isOnlyIfCached())
245         );
246     }
247 
248     @Test
249     public void testParseIsImmutable() {
250         final Header header = new BasicHeader("Cache-Control", "max-age=0 , immutable");
251         final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
252         assertTrue(cacheControl.isImmutable());
253     }
254 
255     @Test
256     public void testParseMultipleIsImmutable() {
257         final Header header = new BasicHeader("Cache-Control", "immutable, nmax-age=0 , immutable");
258         final ResponseCacheControl cacheControl = parser.parseResponse(Collections.singletonList(header).iterator());
259         assertTrue(cacheControl.isImmutable());
260     }
261 
262 }