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.util.Date;
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.impl.classic.ClassicRequestCopier;
40 import org.apache.hc.client5.http.utils.DateUtils;
41 import org.apache.hc.core5.http.ClassicHttpRequest;
42 import org.apache.hc.core5.http.ClassicHttpResponse;
43 import org.apache.hc.core5.http.HttpEntity;
44 import org.apache.hc.core5.http.HttpException;
45 import org.apache.hc.core5.http.HttpHost;
46 import org.apache.hc.core5.http.HttpRequest;
47 import org.apache.hc.core5.http.HttpResponse;
48 import org.apache.hc.core5.http.HttpStatus;
49 import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
50 import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
51 import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
52 import org.easymock.Capture;
53 import org.easymock.EasyMock;
54 import org.junit.Assert;
55 import org.junit.Before;
56 import org.junit.Ignore;
57 import org.junit.Test;
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 @SuppressWarnings("boxing")
74 public class TestProtocolDeviations {
75
76 private static final int MAX_BYTES = 1024;
77 private static final int MAX_ENTRIES = 100;
78
79 private HttpHost host;
80 private HttpRoute route;
81 private HttpEntity mockEntity;
82 private ExecRuntime mockEndpoint;
83 private ExecChain mockExecChain;
84 private HttpCache mockCache;
85 private ClassicHttpRequest request;
86 private HttpCacheContext context;
87 private ClassicHttpResponse originResponse;
88
89 private ExecChainHandler impl;
90
91 @Before
92 public void setUp() {
93 host = new HttpHost("foo.example.com", 80);
94
95 route = new HttpRoute(host);
96
97 request = new BasicClassicHttpRequest("GET", "/foo");
98
99 context = HttpCacheContext.create();
100
101 originResponse = make200Response();
102
103 final CacheConfig config = CacheConfig.custom()
104 .setMaxCacheEntries(MAX_ENTRIES)
105 .setMaxObjectSize(MAX_BYTES)
106 .build();
107
108 final HttpCache cache = new BasicHttpCache(config);
109 mockEndpoint = EasyMock.createNiceMock(ExecRuntime.class);
110 mockExecChain = EasyMock.createNiceMock(ExecChain.class);
111 mockEntity = EasyMock.createNiceMock(HttpEntity.class);
112 mockCache = EasyMock.createNiceMock(HttpCache.class);
113
114 impl = createCachingExecChain(cache, config);
115 }
116
117 private ClassicHttpResponse execute(final ClassicHttpRequest request) throws IOException, HttpException {
118 return impl.execute(ClassicRequestCopier.INSTANCE.copy(request), new ExecChain.Scope(
119 "test", route, request, mockEndpoint, context), mockExecChain);
120 }
121
122 protected ExecChainHandler createCachingExecChain(final HttpCache cache, final CacheConfig config) {
123 return new CachingExec(cache, null, config);
124 }
125
126 private ClassicHttpResponse make200Response() {
127 final ClassicHttpResponse out = new BasicClassicHttpResponse(HttpStatus.SC_OK, "OK");
128 out.setHeader("Date", DateUtils.formatDate(new Date()));
129 out.setHeader("Server", "MockOrigin/1.0");
130 out.setEntity(makeBody(128));
131 return out;
132 }
133
134 private void replayMocks() {
135 EasyMock.replay(mockExecChain);
136 EasyMock.replay(mockCache);
137 EasyMock.replay(mockEntity);
138 }
139
140 private void verifyMocks() {
141 EasyMock.verify(mockExecChain);
142 EasyMock.verify(mockCache);
143 EasyMock.verify(mockEntity);
144 }
145
146 private HttpEntity makeBody(final int nbytes) {
147 final byte[] bytes = new byte[nbytes];
148 new Random().nextBytes(bytes);
149 return new ByteArrayEntity(bytes, null);
150 }
151
152 public static HttpRequest eqRequest(final HttpRequest in) {
153 org.easymock.EasyMock.reportMatcher(new RequestEquivalent(in));
154 return null;
155 }
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 @Ignore
175 public void testHTTP1_1RequestsWithBodiesOfKnownLengthMustHaveContentLength() throws Exception {
176 final ClassicHttpRequest post = new BasicClassicHttpRequest("POST", "/");
177 post.setEntity(mockEntity);
178
179 replayMocks();
180
181 final HttpResponse response = execute(post);
182
183 verifyMocks();
184
185 Assert.assertEquals(HttpStatus.SC_LENGTH_REQUIRED, response.getCode());
186 }
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211 @Ignore
212 public void testHTTP1_1RequestsWithUnknownBodyLengthAreRejectedOrHaveContentLengthAdded()
213 throws Exception {
214 final ClassicHttpRequest post = new BasicClassicHttpRequest("POST", "/");
215
216 final byte[] bytes = new byte[128];
217 new Random().nextBytes(bytes);
218
219 final HttpEntity mockBody = EasyMock.createMockBuilder(ByteArrayEntity.class).withConstructor(
220 new Object[] { bytes }).addMockedMethods("getContentLength").createNiceMock();
221 org.easymock.EasyMock.expect(mockBody.getContentLength()).andReturn(-1L).anyTimes();
222 post.setEntity(mockBody);
223
224 final Capture<ClassicHttpRequest> reqCap = EasyMock.newCapture();
225 EasyMock.expect(
226 mockExecChain.proceed(
227 EasyMock.capture(reqCap),
228 EasyMock.isA(ExecChain.Scope.class))).andReturn(
229 originResponse).times(0, 1);
230
231 replayMocks();
232 EasyMock.replay(mockBody);
233
234 final HttpResponse result = execute(post);
235
236 verifyMocks();
237 EasyMock.verify(mockBody);
238
239 if (reqCap.hasCaptured()) {
240
241 final HttpRequest forwarded = reqCap.getValue();
242 Assert.assertNotNull(forwarded.getFirstHeader("Content-Length"));
243 } else {
244 final int status = result.getCode();
245 Assert.assertTrue(HttpStatus.SC_LENGTH_REQUIRED == status
246 || HttpStatus.SC_BAD_REQUEST == status);
247 }
248 }
249
250
251
252
253
254
255
256
257
258 @Test
259 public void testPartialContentIsNotReturnedToAClientThatDidNotAskForIt() throws Exception {
260
261
262
263
264 request.removeHeaders("Range");
265 originResponse = new BasicClassicHttpResponse(HttpStatus.SC_PARTIAL_CONTENT, "Partial Content");
266 originResponse.setHeader("Content-Range", "bytes 0-499/1234");
267 originResponse.setEntity(makeBody(500));
268
269 EasyMock.expect(
270 mockExecChain.proceed(
271 EasyMock.isA(ClassicHttpRequest.class),
272 EasyMock.isA(ExecChain.Scope.class))).andReturn(originResponse);
273
274 replayMocks();
275 try {
276 final HttpResponse result = execute(request);
277 Assert.assertTrue(HttpStatus.SC_PARTIAL_CONTENT != result.getCode());
278 } catch (final ClientProtocolException acceptableBehavior) {
279
280 }
281 }
282
283
284
285
286
287
288
289
290 @Test
291 public void testPassesOnOrigin401ResponseWithoutWWWAuthenticateHeader() throws Exception {
292
293 originResponse = new BasicClassicHttpResponse(401, "Unauthorized");
294
295 EasyMock.expect(
296 mockExecChain.proceed(
297 EasyMock.isA(ClassicHttpRequest.class),
298 EasyMock.isA(ExecChain.Scope.class))).andReturn(originResponse);
299 replayMocks();
300 final HttpResponse result = execute(request);
301 verifyMocks();
302 Assert.assertSame(originResponse, result);
303 }
304
305
306
307
308
309
310
311 @Test
312 public void testPassesOnOrigin405WithoutAllowHeader() throws Exception {
313 originResponse = new BasicClassicHttpResponse(405, "Method Not Allowed");
314
315 EasyMock.expect(
316 mockExecChain.proceed(
317 EasyMock.isA(ClassicHttpRequest.class),
318 EasyMock.isA(ExecChain.Scope.class))).andReturn(originResponse);
319 replayMocks();
320 final HttpResponse result = execute(request);
321 verifyMocks();
322 Assert.assertSame(originResponse, result);
323 }
324
325
326
327
328
329
330
331
332 @Test
333 public void testPassesOnOrigin407WithoutAProxyAuthenticateHeader() throws Exception {
334 originResponse = new BasicClassicHttpResponse(407, "Proxy Authentication Required");
335
336 EasyMock.expect(
337 mockExecChain.proceed(
338 EasyMock.isA(ClassicHttpRequest.class),
339 EasyMock.isA(ExecChain.Scope.class))).andReturn(originResponse);
340 replayMocks();
341 final HttpResponse result = execute(request);
342 verifyMocks();
343 Assert.assertSame(originResponse, result);
344 }
345
346 }