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 package org.apache.hc.client5.http.impl.cache;
28
29 import java.io.IOException;
30 import java.time.Instant;
31 import java.util.Random;
32
33 import org.apache.hc.client5.http.ClientProtocolException;
34 import org.apache.hc.client5.http.HttpRoute;
35 import org.apache.hc.client5.http.cache.HttpCacheContext;
36 import org.apache.hc.client5.http.classic.ExecChain;
37 import org.apache.hc.client5.http.classic.ExecChainHandler;
38 import org.apache.hc.client5.http.classic.ExecRuntime;
39 import org.apache.hc.client5.http.utils.DateUtils;
40 import org.apache.hc.core5.http.ClassicHttpRequest;
41 import org.apache.hc.core5.http.ClassicHttpResponse;
42 import org.apache.hc.core5.http.HttpEntity;
43 import org.apache.hc.core5.http.HttpException;
44 import org.apache.hc.core5.http.HttpHost;
45 import org.apache.hc.core5.http.HttpResponse;
46 import org.apache.hc.core5.http.HttpStatus;
47 import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
48 import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
49 import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
50 import org.junit.jupiter.api.Assertions;
51 import org.junit.jupiter.api.BeforeEach;
52 import org.junit.jupiter.api.Test;
53 import org.mockito.Mock;
54 import org.mockito.Mockito;
55 import org.mockito.MockitoAnnotations;
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 @SuppressWarnings("boxing")
72 public class TestProtocolDeviations {
73
74 private static final int MAX_BYTES = 1024;
75 private static final int MAX_ENTRIES = 100;
76
77 HttpHost host;
78 HttpRoute route;
79 @Mock
80 ExecRuntime mockEndpoint;
81 @Mock
82 ExecChain mockExecChain;
83 ClassicHttpRequest request;
84 HttpCacheContext context;
85 ClassicHttpResponse originResponse;
86
87 ExecChainHandler impl;
88
89 @BeforeEach
90 public void setUp() {
91 MockitoAnnotations.openMocks(this);
92 host = new HttpHost("foo.example.com", 80);
93
94 route = new HttpRoute(host);
95
96 request = new BasicClassicHttpRequest("GET", "/foo");
97
98 context = HttpCacheContext.create();
99
100 originResponse = make200Response();
101
102 final CacheConfig config = CacheConfig.custom()
103 .setMaxCacheEntries(MAX_ENTRIES)
104 .setMaxObjectSize(MAX_BYTES)
105 .build();
106
107 final HttpCache cache = new BasicHttpCache(config);
108 impl = createCachingExecChain(cache, config);
109 }
110
111 private ClassicHttpResponse execute(final ClassicHttpRequest request) throws IOException, HttpException {
112 return impl.execute(request,
113 new ExecChain.Scope("test", route, request, mockEndpoint, context),
114 mockExecChain);
115 }
116
117 protected ExecChainHandler createCachingExecChain(final HttpCache cache, final CacheConfig config) {
118 return new CachingExec(cache, null, config);
119 }
120
121 private ClassicHttpResponse make200Response() {
122 final ClassicHttpResponse out = new BasicClassicHttpResponse(HttpStatus.SC_OK, "OK");
123 out.setHeader("Date", DateUtils.formatStandardDate(Instant.now()));
124 out.setHeader("Server", "MockOrigin/1.0");
125 out.setEntity(makeBody(128));
126 return out;
127 }
128
129 private HttpEntity makeBody(final int nbytes) {
130 final byte[] bytes = new byte[nbytes];
131 new Random().nextBytes(bytes);
132 return new ByteArrayEntity(bytes, null);
133 }
134
135
136
137
138
139
140
141
142
143 @Test
144 public void testPartialContentIsNotReturnedToAClientThatDidNotAskForIt() throws Exception {
145
146
147
148
149 request.removeHeaders("Range");
150 originResponse = new BasicClassicHttpResponse(HttpStatus.SC_PARTIAL_CONTENT, "Partial Content");
151 originResponse.setHeader("Content-Range", "bytes 0-499/1234");
152 originResponse.setEntity(makeBody(500));
153
154 Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
155
156 try {
157 final HttpResponse result = execute(request);
158 Assertions.assertTrue(HttpStatus.SC_PARTIAL_CONTENT != result.getCode());
159 } catch (final ClientProtocolException acceptableBehavior) {
160
161 }
162 }
163
164
165
166
167
168
169
170
171 @Test
172 public void testPassesOnOrigin401ResponseWithoutWWWAuthenticateHeader() throws Exception {
173
174 originResponse = new BasicClassicHttpResponse(401, "Unauthorized");
175
176 Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
177
178 final HttpResponse result = execute(request);
179 Assertions.assertSame(originResponse, result);
180 }
181
182
183
184
185
186
187
188 @Test
189 public void testPassesOnOrigin405WithoutAllowHeader() throws Exception {
190 originResponse = new BasicClassicHttpResponse(405, "Method Not Allowed");
191
192 Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
193
194 final HttpResponse result = execute(request);
195 Assertions.assertSame(originResponse, result);
196 }
197
198
199
200
201
202
203
204
205 @Test
206 public void testPassesOnOrigin407WithoutAProxyAuthenticateHeader() throws Exception {
207 originResponse = new BasicClassicHttpResponse(407, "Proxy Authentication Required");
208
209 Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
210
211 final HttpResponse result = execute(request);
212 Assertions.assertSame(originResponse, result);
213 }
214
215 }