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.UnsupportedEncodingException;
30 import java.net.URI;
31 import java.net.URISyntaxException;
32 import java.net.URLEncoder;
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.List;
36
37 import org.apache.http.Consts;
38 import org.apache.http.Header;
39 import org.apache.http.HeaderElement;
40 import org.apache.http.HttpHost;
41 import org.apache.http.HttpRequest;
42 import org.apache.http.annotation.Contract;
43 import org.apache.http.annotation.ThreadingBehavior;
44 import org.apache.http.client.cache.HeaderConstants;
45 import org.apache.http.client.cache.HttpCacheEntry;
46 import org.apache.http.client.methods.HttpUriRequest;
47 import org.apache.http.client.utils.URIBuilder;
48 import org.apache.http.client.utils.URIUtils;
49 import org.apache.http.client.utils.URLEncodedUtils;
50 import org.apache.http.util.Args;
51
52
53
54
55 @Contract(threading = ThreadingBehavior.IMMUTABLE)
56 class CacheKeyGenerator {
57
58 private static final URI BASE_URI = URI.create("http://example.com/");
59
60 static URIBuilder getRequestUriBuilder(final HttpRequest request) throws URISyntaxException {
61 if (request instanceof HttpUriRequest) {
62 final URI uri = ((HttpUriRequest) request).getURI();
63 if (uri != null) {
64 return new URIBuilder(uri);
65 }
66 }
67 return new URIBuilder(request.getRequestLine().getUri());
68 }
69
70 static URI getRequestUri(final HttpRequest request, final HttpHost target) throws URISyntaxException {
71 Args.notNull(request, "HTTP request");
72 Args.notNull(target, "Target");
73 final URIBuilder uriBuilder = getRequestUriBuilder(request);
74
75
76 final String path = uriBuilder.getPath();
77 if (path != null) {
78 uriBuilder.setPathSegments(URLEncodedUtils.parsePathSegments(path));
79 }
80
81 if (!uriBuilder.isAbsolute()) {
82 uriBuilder.setScheme(target.getSchemeName());
83 uriBuilder.setHost(target.getHostName());
84 uriBuilder.setPort(target.getPort());
85 }
86 return uriBuilder.build();
87 }
88
89 static URI normalize(final URI requestUri) throws URISyntaxException {
90 Args.notNull(requestUri, "URI");
91 final URIBuilder builder = new URIBuilder(requestUri.isAbsolute() ? URIUtils.resolve(BASE_URI, requestUri) : requestUri) ;
92 if (builder.getHost() != null) {
93 if (builder.getScheme() == null) {
94 builder.setScheme("http");
95 }
96 if (builder.getPort() <= -1) {
97 if ("http".equalsIgnoreCase(builder.getScheme())) {
98 builder.setPort(80);
99 } else if ("https".equalsIgnoreCase(builder.getScheme())) {
100 builder.setPort(443);
101 }
102 }
103 }
104 builder.setFragment(null);
105 return builder.build();
106 }
107
108
109
110
111
112
113
114
115
116 public String getURI(final HttpHost host, final HttpRequest req) {
117 try {
118 final URI uri = normalize(getRequestUri(req, host));
119 return uri.toASCIIString();
120 } catch (final URISyntaxException ex) {
121 return req.getRequestLine().getUri();
122 }
123 }
124
125 public String canonicalizeUri(final String uri) {
126 try {
127 final URI normalized = normalize(URIUtils.resolve(BASE_URI, uri));
128 return normalized.toASCIIString();
129 } catch (final URISyntaxException ex) {
130 return uri;
131 }
132 }
133
134 protected String getFullHeaderValue(final Header[] headers) {
135 if (headers == null) {
136 return "";
137 }
138
139 final StringBuilder buf = new StringBuilder("");
140 boolean first = true;
141 for (final Header hdr : headers) {
142 if (!first) {
143 buf.append(", ");
144 }
145 buf.append(hdr.getValue().trim());
146 first = false;
147
148 }
149 return buf.toString();
150 }
151
152
153
154
155
156
157
158
159
160
161
162 public String getVariantURI(final HttpHost host, final HttpRequest req, final HttpCacheEntry entry) {
163 if (!entry.hasVariants()) {
164 return getURI(host, req);
165 }
166 return getVariantKey(req, entry) + getURI(host, req);
167 }
168
169
170
171
172
173
174
175
176
177
178 public String getVariantKey(final HttpRequest req, final HttpCacheEntry entry) {
179 final List<String> variantHeaderNames = new ArrayList<String>();
180 for (final Header varyHdr : entry.getHeaders(HeaderConstants.VARY)) {
181 for (final HeaderElement elt : varyHdr.getElements()) {
182 variantHeaderNames.add(elt.getName());
183 }
184 }
185 Collections.sort(variantHeaderNames);
186
187 final StringBuilder buf;
188 try {
189 buf = new StringBuilder("{");
190 boolean first = true;
191 for (final String headerName : variantHeaderNames) {
192 if (!first) {
193 buf.append("&");
194 }
195 buf.append(URLEncoder.encode(headerName, Consts.UTF_8.name()));
196 buf.append("=");
197 buf.append(URLEncoder.encode(getFullHeaderValue(req.getHeaders(headerName)),
198 Consts.UTF_8.name()));
199 first = false;
200 }
201 buf.append("}");
202 } catch (final UnsupportedEncodingException uee) {
203 throw new RuntimeException("couldn't encode to UTF-8", uee);
204 }
205 return buf.toString();
206 }
207
208 }