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.http.impl.client.cache;
28
29 import java.util.Date;
30 import java.util.Random;
31
32 import org.apache.http.HttpEntity;
33 import org.apache.http.HttpEntityEnclosingRequest;
34 import org.apache.http.HttpHost;
35 import org.apache.http.HttpRequest;
36 import org.apache.http.HttpResponse;
37 import org.apache.http.HttpStatus;
38 import org.apache.http.ProtocolVersion;
39 import org.apache.http.client.ClientProtocolException;
40 import org.apache.http.client.cache.HttpCacheContext;
41 import org.apache.http.client.methods.CloseableHttpResponse;
42 import org.apache.http.client.methods.HttpExecutionAware;
43 import org.apache.http.client.methods.HttpRequestWrapper;
44 import org.apache.http.client.protocol.HttpClientContext;
45 import org.apache.http.client.utils.DateUtils;
46 import org.apache.http.conn.routing.HttpRoute;
47 import org.apache.http.entity.ByteArrayEntity;
48 import org.apache.http.impl.execchain.ClientExecChain;
49 import org.apache.http.message.BasicHttpEntityEnclosingRequest;
50 import org.apache.http.message.BasicHttpRequest;
51 import org.apache.http.message.BasicHttpResponse;
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 ProtocolVersion HTTP_1_1 = new ProtocolVersion("HTTP", 1, 1);
77
78 private static final int MAX_BYTES = 1024;
79 private static final int MAX_ENTRIES = 100;
80 private final int entityLength = 128;
81
82 private HttpHost host;
83 private HttpRoute route;
84 private HttpEntity body;
85 private HttpEntity mockEntity;
86 private ClientExecChain mockBackend;
87 private HttpCache mockCache;
88 private HttpRequest request;
89 private HttpCacheContext context;
90 private CloseableHttpResponse originResponse;
91
92 private ClientExecChain impl;
93
94 @Before
95 public void setUp() {
96 host = new HttpHost("foo.example.com", 80);
97
98 route = new HttpRoute(host);
99
100 body = makeBody(entityLength);
101
102 request = new BasicHttpRequest("GET", "/foo", HTTP_1_1);
103
104 context = HttpCacheContext.create();
105 context.setTargetHost(host);
106
107 originResponse = Proxies.enhanceResponse(make200Response());
108
109 final CacheConfig config = CacheConfig.custom()
110 .setMaxCacheEntries(MAX_ENTRIES)
111 .setMaxObjectSize(MAX_BYTES)
112 .build();
113
114 final HttpCache cache = new BasicHttpCache(config);
115 mockBackend = EasyMock.createNiceMock(ClientExecChain.class);
116 mockEntity = EasyMock.createNiceMock(HttpEntity.class);
117 mockCache = EasyMock.createNiceMock(HttpCache.class);
118
119 impl = createCachingExecChain(mockBackend, cache, config);
120 }
121
122 protected ClientExecChain createCachingExecChain(
123 final ClientExecChain backend, final HttpCache cache, final CacheConfig config) {
124 return new CachingExec(backend, cache, config);
125 }
126
127 private HttpResponse make200Response() {
128 final HttpResponse out = new BasicHttpResponse(HTTP_1_1, HttpStatus.SC_OK, "OK");
129 out.setHeader("Date", DateUtils.formatDate(new Date()));
130 out.setHeader("Server", "MockOrigin/1.0");
131 out.setEntity(makeBody(128));
132 return out;
133 }
134
135 private void replayMocks() {
136 EasyMock.replay(mockBackend);
137 EasyMock.replay(mockCache);
138 EasyMock.replay(mockEntity);
139 }
140
141 private void verifyMocks() {
142 EasyMock.verify(mockBackend);
143 EasyMock.verify(mockCache);
144 EasyMock.verify(mockEntity);
145 }
146
147 private HttpEntity makeBody(final int nbytes) {
148 final byte[] bytes = new byte[nbytes];
149 new Random().nextBytes(bytes);
150 return new ByteArrayEntity(bytes);
151 }
152
153 public static HttpRequest eqRequest(final HttpRequest in) {
154 org.easymock.EasyMock.reportMatcher(new RequestEquivalent(in));
155 return null;
156 }
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175 @Ignore
176 public void testHTTP1_1RequestsWithBodiesOfKnownLengthMustHaveContentLength() throws Exception {
177 final BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/",
178 HTTP_1_1);
179 post.setEntity(mockEntity);
180
181 replayMocks();
182
183 final HttpResponse response = impl.execute(route, HttpRequestWrapper.wrap(post), context, null);
184
185 verifyMocks();
186
187 Assert
188 .assertEquals(HttpStatus.SC_LENGTH_REQUIRED, response.getStatusLine()
189 .getStatusCode());
190 }
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215 @Ignore
216 public void testHTTP1_1RequestsWithUnknownBodyLengthAreRejectedOrHaveContentLengthAdded()
217 throws Exception {
218 final BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/",
219 HTTP_1_1);
220
221 final byte[] bytes = new byte[128];
222 new Random().nextBytes(bytes);
223
224 final HttpEntity mockBody = org.easymock.classextension.EasyMock.createMockBuilder(ByteArrayEntity.class).withConstructor(
225 new Object[] { bytes }).addMockedMethods("getContentLength").createNiceMock();
226 org.easymock.EasyMock.expect(mockBody.getContentLength()).andReturn(-1L).anyTimes();
227 post.setEntity(mockBody);
228
229 final Capture<HttpRequestWrapper> reqCap = new Capture<HttpRequestWrapper>();
230 EasyMock.expect(
231 mockBackend.execute(
232 EasyMock.eq(route),
233 EasyMock.capture(reqCap),
234 EasyMock.isA(HttpClientContext.class),
235 EasyMock.<HttpExecutionAware>isNull())).andReturn(
236 originResponse).times(0, 1);
237
238 replayMocks();
239 EasyMock.replay(mockBody);
240
241 final HttpResponse result = impl.execute(route, HttpRequestWrapper.wrap(post), context, null);
242
243 verifyMocks();
244 EasyMock.verify(mockBody);
245
246 if (reqCap.hasCaptured()) {
247
248 final HttpRequest forwarded = reqCap.getValue();
249 Assert.assertNotNull(forwarded.getFirstHeader("Content-Length"));
250 } else {
251 final int status = result.getStatusLine().getStatusCode();
252 Assert.assertTrue(HttpStatus.SC_LENGTH_REQUIRED == status
253 || HttpStatus.SC_BAD_REQUEST == status);
254 }
255 }
256
257
258
259
260
261
262
263
264 @Test
265 public void testOPTIONSRequestsWithBodiesAndNoContentTypeHaveOneSupplied() throws Exception {
266 final BasicHttpEntityEnclosingRequest options = new BasicHttpEntityEnclosingRequest("OPTIONS",
267 "/", HTTP_1_1);
268 options.setEntity(body);
269 options.setHeader("Content-Length", "1");
270
271 final Capture<HttpRequestWrapper> reqCap = new Capture<HttpRequestWrapper>();
272 EasyMock.expect(
273 mockBackend.execute(
274 EasyMock.eq(route),
275 EasyMock.capture(reqCap),
276 EasyMock.isA(HttpClientContext.class),
277 EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
278 replayMocks();
279
280 impl.execute(route, HttpRequestWrapper.wrap(options), context, null);
281
282 verifyMocks();
283
284 final HttpRequest forwarded = reqCap.getValue();
285 Assert.assertTrue(forwarded instanceof HttpEntityEnclosingRequest);
286 final HttpEntityEnclosingRequest reqWithBody = (HttpEntityEnclosingRequest) forwarded;
287 final HttpEntity reqBody = reqWithBody.getEntity();
288 Assert.assertNotNull(reqBody);
289 Assert.assertNotNull(reqBody.getContentType());
290 }
291
292
293
294
295
296
297
298
299
300 @Test
301 public void testPartialContentIsNotReturnedToAClientThatDidNotAskForIt() throws Exception {
302
303
304
305
306 request.removeHeaders("Range");
307 originResponse = Proxies.enhanceResponse(
308 new BasicHttpResponse(HTTP_1_1, HttpStatus.SC_PARTIAL_CONTENT,
309 "Partial Content"));
310 originResponse.setHeader("Content-Range", "bytes 0-499/1234");
311 originResponse.setEntity(makeBody(500));
312
313 EasyMock.expect(
314 mockBackend.execute(
315 EasyMock.eq(route),
316 EasyMock.isA(HttpRequestWrapper.class),
317 EasyMock.isA(HttpClientContext.class),
318 EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
319
320 replayMocks();
321 try {
322 final HttpResponse result = impl.execute(route, HttpRequestWrapper.wrap(request), context, null);
323 Assert.assertTrue(HttpStatus.SC_PARTIAL_CONTENT != result.getStatusLine()
324 .getStatusCode());
325 } catch (final ClientProtocolException acceptableBehavior) {
326
327 }
328 }
329
330
331
332
333
334
335
336
337 @Test
338 public void testPassesOnOrigin401ResponseWithoutWWWAuthenticateHeader() throws Exception {
339
340 originResponse = Proxies.enhanceResponse(
341 new BasicHttpResponse(HTTP_1_1, 401, "Unauthorized"));
342
343 EasyMock.expect(
344 mockBackend.execute(
345 EasyMock.eq(route),
346 EasyMock.isA(HttpRequestWrapper.class),
347 EasyMock.isA(HttpClientContext.class),
348 EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
349 replayMocks();
350 final HttpResponse result = impl.execute(route, HttpRequestWrapper.wrap(request), context, null);
351 verifyMocks();
352 Assert.assertSame(originResponse, result);
353 }
354
355
356
357
358
359
360
361 @Test
362 public void testPassesOnOrigin405WithoutAllowHeader() throws Exception {
363 originResponse = Proxies.enhanceResponse(
364 new BasicHttpResponse(HTTP_1_1, 405, "Method Not Allowed"));
365
366 EasyMock.expect(
367 mockBackend.execute(
368 EasyMock.eq(route),
369 EasyMock.isA(HttpRequestWrapper.class),
370 EasyMock.isA(HttpClientContext.class),
371 EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
372 replayMocks();
373 final HttpResponse result = impl.execute(route, HttpRequestWrapper.wrap(request), context, null);
374 verifyMocks();
375 Assert.assertSame(originResponse, result);
376 }
377
378
379
380
381
382
383
384
385 @Test
386 public void testPassesOnOrigin407WithoutAProxyAuthenticateHeader() throws Exception {
387 originResponse = Proxies.enhanceResponse(
388 new BasicHttpResponse(HTTP_1_1, 407, "Proxy Authentication Required"));
389
390 EasyMock.expect(
391 mockBackend.execute(
392 EasyMock.eq(route),
393 EasyMock.isA(HttpRequestWrapper.class),
394 EasyMock.isA(HttpClientContext.class),
395 EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
396 replayMocks();
397 final HttpResponse result = impl.execute(route, HttpRequestWrapper.wrap(request), context, null);
398 verifyMocks();
399 Assert.assertSame(originResponse, result);
400 }
401
402 }