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.io.InputStream;
30 import java.util.Date;
31 import java.util.HashMap;
32 import java.util.Map;
33 import java.util.Random;
34
35 import org.apache.http.Header;
36 import org.apache.http.HeaderElement;
37 import org.apache.http.HttpEntity;
38 import org.apache.http.HttpMessage;
39 import org.apache.http.HttpRequest;
40 import org.apache.http.HttpResponse;
41 import org.apache.http.HttpStatus;
42 import org.apache.http.HttpVersion;
43 import org.apache.http.RequestLine;
44 import org.apache.http.StatusLine;
45 import org.apache.http.client.cache.HeaderConstants;
46 import org.apache.http.client.cache.HttpCacheEntry;
47 import org.apache.http.client.utils.DateUtils;
48 import org.apache.http.entity.ByteArrayEntity;
49 import org.apache.http.message.BasicHeader;
50 import org.apache.http.message.BasicHttpRequest;
51 import org.apache.http.message.BasicHttpResponse;
52 import org.apache.http.message.BasicStatusLine;
53 import org.junit.Assert;
54
55 public class HttpTestUtils {
56
57
58
59
60
61
62 private static final String[] HOP_BY_HOP_HEADERS = { "Connection", "Keep-Alive", "Proxy-Authenticate",
63 "Proxy-Authorization", "TE", "Trailers", "Transfer-Encoding", "Upgrade" };
64
65
66
67
68
69
70
71
72 private static final String[] MULTI_HEADERS = { "Accept", "Accept-Charset", "Accept-Encoding",
73 "Accept-Language", "Allow", "Cache-Control", "Connection", "Content-Encoding",
74 "Content-Language", "Expect", "Pragma", "Proxy-Authenticate", "TE", "Trailer",
75 "Transfer-Encoding", "Upgrade", "Via", "Warning", "WWW-Authenticate" };
76 private static final String[] SINGLE_HEADERS = { "Accept-Ranges", "Age", "Authorization",
77 "Content-Length", "Content-Location", "Content-MD5", "Content-Range", "Content-Type",
78 "Date", "ETag", "Expires", "From", "Host", "If-Match", "If-Modified-Since",
79 "If-None-Match", "If-Range", "If-Unmodified-Since", "Last-Modified", "Location",
80 "Max-Forwards", "Proxy-Authorization", "Range", "Referer", "Retry-After", "Server",
81 "User-Agent", "Vary" };
82
83
84
85
86
87
88
89 public static final String[] ENTITY_HEADERS = { "Allow", "Content-Encoding",
90 "Content-Language", "Content-Length", "Content-Location", "Content-MD5",
91 "Content-Range", "Content-Type", "Expires", "Last-Modified" };
92
93
94
95
96
97
98
99 public static boolean isHopByHopHeader(final String name) {
100 for (final String s : HOP_BY_HOP_HEADERS) {
101 if (s.equalsIgnoreCase(name)) {
102 return true;
103 }
104 }
105 return false;
106 }
107
108
109
110
111 public static boolean isMultiHeader(final String name) {
112 for (final String s : MULTI_HEADERS) {
113 if (s.equalsIgnoreCase(name)) {
114 return true;
115 }
116 }
117 return false;
118 }
119
120
121
122
123 public static boolean isSingleHeader(final String name) {
124 for (final String s : SINGLE_HEADERS) {
125 if (s.equalsIgnoreCase(name)) {
126 return true;
127 }
128 }
129 return false;
130 }
131
132
133
134 public static boolean equivalent(final HttpEntity e1, final HttpEntity e2) throws Exception {
135 final InputStream i1 = e1.getContent();
136 final InputStream i2 = e2.getContent();
137 if (i1 == null && i2 == null) {
138 return true;
139 }
140 if (i1 == null || i2 == null)
141 {
142 return false;
143 }
144 int b1 = -1;
145 while ((b1 = i1.read()) != -1) {
146 if (b1 != i2.read()) {
147 return false;
148 }
149 }
150 return (-1 == i2.read());
151 }
152
153
154
155
156
157
158
159
160
161 public static boolean semanticallyTransparent(final StatusLine l1, final StatusLine l2) {
162 return (l1.getReasonPhrase().equals(l2.getReasonPhrase()) && l1.getStatusCode() == l2
163 .getStatusCode());
164 }
165
166
167 public static boolean equivalent(final StatusLine l1, final StatusLine l2) {
168 return (l1.getProtocolVersion().equals(l2.getProtocolVersion()) && semanticallyTransparent(
169 l1, l2));
170 }
171
172
173 public static boolean equivalent(final RequestLine l1, final RequestLine l2) {
174 return (l1.getMethod().equals(l2.getMethod())
175 && l1.getProtocolVersion().equals(l2.getProtocolVersion()) && l1.getUri().equals(
176 l2.getUri()));
177 }
178
179
180
181
182
183
184
185 public static String getCanonicalHeaderValue(final HttpMessage r, final String name) {
186 if (isSingleHeader(name)) {
187 final Header h = r.getFirstHeader(name);
188 return (h != null) ? h.getValue() : null;
189 }
190 final StringBuilder buf = new StringBuilder();
191 boolean first = true;
192 for (final Header h : r.getHeaders(name)) {
193 if (!first) {
194 buf.append(", ");
195 }
196 buf.append(h.getValue().trim());
197 first = false;
198 }
199 return buf.toString();
200 }
201
202
203
204
205
206 public static boolean isEndToEndHeaderSubset(final HttpMessage r1, final HttpMessage r2) {
207 for (final Header h : r1.getAllHeaders()) {
208 if (!isHopByHopHeader(h.getName())) {
209 final String r1val = getCanonicalHeaderValue(r1, h.getName());
210 final String r2val = getCanonicalHeaderValue(r2, h.getName());
211 if (!r1val.equals(r2val)) {
212 return false;
213 }
214 }
215 }
216 return true;
217 }
218
219
220
221
222
223
224
225
226
227
228 public static boolean semanticallyTransparent(final HttpResponse r1, final HttpResponse r2)
229 throws Exception {
230 final boolean entitiesEquivalent = equivalent(r1.getEntity(), r2.getEntity());
231 if (!entitiesEquivalent) {
232 return false;
233 }
234 final boolean statusLinesEquivalent = semanticallyTransparent(r1.getStatusLine(), r2.getStatusLine());
235 if (!statusLinesEquivalent) {
236 return false;
237 }
238 final boolean e2eHeadersEquivalentSubset = isEndToEndHeaderSubset(
239 r1, r2);
240 return e2eHeadersEquivalentSubset;
241 }
242
243
244 public static boolean equivalent(final HttpRequest r1, final HttpRequest r2) {
245 return (equivalent(r1.getRequestLine(), r2.getRequestLine()) && isEndToEndHeaderSubset(r1,
246 r2));
247 }
248
249
250 public static boolean equivalent(final HttpResponse r1, final HttpResponse r2) {
251 return (equivalent(r1.getStatusLine(), r2.getStatusLine()) && isEndToEndHeaderSubset(r1,
252 r2));
253 }
254
255 public static byte[] getRandomBytes(final int nbytes) {
256 final byte[] bytes = new byte[nbytes];
257 new Random().nextBytes(bytes);
258 return bytes;
259 }
260
261
262
263
264
265 public static HttpEntity makeBody(final int nbytes) {
266 return new ByteArrayEntity(getRandomBytes(nbytes));
267 }
268
269 public static HttpCacheEntry makeCacheEntry(final Date requestDate, final Date responseDate) {
270 final Date when = new Date((responseDate.getTime() + requestDate.getTime()) / 2);
271 return makeCacheEntry(requestDate, responseDate, getStockHeaders(when));
272 }
273
274 public static Header[] getStockHeaders(final Date when) {
275 final Header[] headers = {
276 new BasicHeader("Date", DateUtils.formatDate(when)),
277 new BasicHeader("Server", "MockServer/1.0")
278 };
279 return headers;
280 }
281
282 public static HttpCacheEntry makeCacheEntry(final Date requestDate,
283 final Date responseDate, final Header[] headers) {
284 final byte[] bytes = getRandomBytes(128);
285 return makeCacheEntry(requestDate, responseDate, headers, bytes);
286 }
287
288 public static HttpCacheEntry makeCacheEntry(final Date requestDate,
289 final Date responseDate, final Header[] headers, final byte[] bytes) {
290 final Map<String,String> variantMap = null;
291 return makeCacheEntry(requestDate, responseDate, headers, bytes,
292 variantMap);
293 }
294
295 public static HttpCacheEntry makeCacheEntry(final Map<String,String> variantMap) {
296 final Date now = new Date();
297 return makeCacheEntry(now, now, getStockHeaders(now),
298 getRandomBytes(128), variantMap);
299 }
300
301 public static HttpCacheEntry makeCacheEntry(final Date requestDate,
302 final Date responseDate, final Header[] headers, final byte[] bytes,
303 final Map<String,String> variantMap) {
304 return new HttpCacheEntry(requestDate, responseDate, makeStatusLine(), headers, new HeapResource(bytes), variantMap, HeaderConstants.GET_METHOD);
305 }
306
307 public static HttpCacheEntry makeCacheEntry(final Header[] headers, final byte[] bytes) {
308 final Date now = new Date();
309 return makeCacheEntry(now, now, headers, bytes);
310 }
311
312 public static HttpCacheEntry makeCacheEntry(final byte[] bytes) {
313 return makeCacheEntry(getStockHeaders(new Date()), bytes);
314 }
315
316 public static HttpCacheEntry makeCacheEntry(final Header[] headers) {
317 return makeCacheEntry(headers, getRandomBytes(128));
318 }
319
320 public static HttpCacheEntry makeCacheEntry() {
321 final Date now = new Date();
322 return makeCacheEntry(now, now);
323 }
324
325 public static HttpCacheEntry makeCacheEntryWithNoRequestMethodOrEntity(final Header[] headers) {
326 final Date now = new Date();
327 return new HttpCacheEntry(now, now, makeStatusLine(), headers, null, null, null);
328 }
329
330 public static HttpCacheEntry makeCacheEntryWithNoRequestMethod(final Header[] headers) {
331 final Date now = new Date();
332 return new HttpCacheEntry(now, now, makeStatusLine(), headers, new HeapResource(getRandomBytes(128)), null, null);
333 }
334
335 public static HttpCacheEntry make204CacheEntryWithNoRequestMethod(final Header[] headers) {
336 final Date now = new Date();
337 return new HttpCacheEntry(now, now, make204StatusLine(), headers, null, null, HeaderConstants.HEAD_METHOD);
338 }
339
340 public static HttpCacheEntry makeHeadCacheEntry(final Header[] headers) {
341 final Date now = new Date();
342 return new HttpCacheEntry(now, now, makeStatusLine(), headers, null, null, HeaderConstants.HEAD_METHOD);
343 }
344
345 public static HttpCacheEntry makeHeadCacheEntryWithNoRequestMethod(final Header[] headers) {
346 final Date now = new Date();
347 return new HttpCacheEntry(now, now, makeStatusLine(), headers, null, null, null);
348 }
349
350 public static StatusLine makeStatusLine() {
351 return new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
352 }
353
354 public static StatusLine make204StatusLine() {
355 return new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_NO_CONTENT, "OK");
356 }
357
358 public static HttpResponse make200Response() {
359 final HttpResponse out = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
360 out.setHeader("Date", DateUtils.formatDate(new Date()));
361 out.setHeader("Server", "MockOrigin/1.0");
362 out.setHeader("Content-Length", "128");
363 out.setEntity(makeBody(128));
364 return out;
365 }
366
367 public static final HttpResponse make200Response(final Date date, final String cacheControl) {
368 final HttpResponse response = HttpTestUtils.make200Response();
369 response.setHeader("Date", DateUtils.formatDate(date));
370 response.setHeader("Cache-Control",cacheControl);
371 response.setHeader("Etag","\"etag\"");
372 return response;
373 }
374
375 public static final void assert110WarningFound(final HttpResponse response) {
376 boolean found110Warning = false;
377 for(final Header h : response.getHeaders("Warning")) {
378 for(final HeaderElement elt : h.getElements()) {
379 final String[] parts = elt.getName().split("\\s");
380 if ("110".equals(parts[0])) {
381 found110Warning = true;
382 break;
383 }
384 }
385 }
386 Assert.assertTrue(found110Warning);
387 }
388
389 public static HttpRequest makeDefaultRequest() {
390 return new BasicHttpRequest("GET","/",HttpVersion.HTTP_1_1);
391 }
392
393 public static HttpRequest makeDefaultHEADRequest() {
394 return new BasicHttpRequest("HEAD","/",HttpVersion.HTTP_1_1);
395 }
396
397 public static HttpResponse make500Response() {
398 return new BasicHttpResponse(HttpVersion.HTTP_1_1,
399 HttpStatus.SC_INTERNAL_SERVER_ERROR, "Internal Server Error");
400 }
401
402 public static Map<String, String> makeDefaultVariantMap(final String key, final String value) {
403 final Map<String, String> variants = new HashMap<String, String>();
404 variants.put(key, value);
405
406 return variants;
407 }
408 }