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
28 package org.apache.http.impl.client;
29
30 import java.net.URI;
31 import java.net.URISyntaxException;
32
33 import org.apache.http.annotation.Immutable;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37 import org.apache.http.Header;
38 import org.apache.http.HttpEntityEnclosingRequest;
39 import org.apache.http.HttpHost;
40 import org.apache.http.HttpRequest;
41 import org.apache.http.HttpResponse;
42 import org.apache.http.HttpStatus;
43 import org.apache.http.ProtocolException;
44 import org.apache.http.client.CircularRedirectException;
45 import org.apache.http.client.RedirectStrategy;
46 import org.apache.http.client.methods.HttpDelete;
47 import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
48 import org.apache.http.client.methods.HttpGet;
49 import org.apache.http.client.methods.HttpHead;
50 import org.apache.http.client.methods.HttpOptions;
51 import org.apache.http.client.methods.HttpPatch;
52 import org.apache.http.client.methods.HttpPost;
53 import org.apache.http.client.methods.HttpPut;
54 import org.apache.http.client.methods.HttpTrace;
55 import org.apache.http.client.methods.HttpUriRequest;
56 import org.apache.http.client.params.ClientPNames;
57 import org.apache.http.client.utils.URIUtils;
58 import org.apache.http.params.HttpParams;
59 import org.apache.http.protocol.HttpContext;
60 import org.apache.http.protocol.ExecutionContext;
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 @Immutable
77 public class DefaultRedirectStrategy implements RedirectStrategy {
78
79 private final Log log = LogFactory.getLog(getClass());
80
81 public static final String REDIRECT_LOCATIONS = "http.protocol.redirect-locations";
82
83
84
85
86 private static final String[] REDIRECT_METHODS = new String[] {
87 HttpGet.METHOD_NAME,
88 HttpHead.METHOD_NAME
89 };
90
91 public DefaultRedirectStrategy() {
92 super();
93 }
94
95 public boolean isRedirected(
96 final HttpRequest request,
97 final HttpResponse response,
98 final HttpContext context) throws ProtocolException {
99 if (request == null) {
100 throw new IllegalArgumentException("HTTP request may not be null");
101 }
102 if (response == null) {
103 throw new IllegalArgumentException("HTTP response may not be null");
104 }
105
106 int statusCode = response.getStatusLine().getStatusCode();
107 String method = request.getRequestLine().getMethod();
108 Header locationHeader = response.getFirstHeader("location");
109 switch (statusCode) {
110 case HttpStatus.SC_MOVED_TEMPORARILY:
111 return isRedirectable(method) && locationHeader != null;
112 case HttpStatus.SC_MOVED_PERMANENTLY:
113 case HttpStatus.SC_TEMPORARY_REDIRECT:
114 return isRedirectable(method);
115 case HttpStatus.SC_SEE_OTHER:
116 return true;
117 default:
118 return false;
119 }
120 }
121
122 public URI getLocationURI(
123 final HttpRequest request,
124 final HttpResponse response,
125 final HttpContext context) throws ProtocolException {
126 if (request == null) {
127 throw new IllegalArgumentException("HTTP request may not be null");
128 }
129 if (response == null) {
130 throw new IllegalArgumentException("HTTP response may not be null");
131 }
132 if (context == null) {
133 throw new IllegalArgumentException("HTTP context may not be null");
134 }
135
136 Header locationHeader = response.getFirstHeader("location");
137 if (locationHeader == null) {
138
139 throw new ProtocolException(
140 "Received redirect response " + response.getStatusLine()
141 + " but no location header");
142 }
143 String location = locationHeader.getValue();
144 if (this.log.isDebugEnabled()) {
145 this.log.debug("Redirect requested to location '" + location + "'");
146 }
147
148 URI uri = createLocationURI(location);
149
150 HttpParams params = request.getParams();
151
152
153 try {
154
155 uri = URIUtils.rewriteURI(uri);
156 if (!uri.isAbsolute()) {
157 if (params.isParameterTrue(ClientPNames.REJECT_RELATIVE_REDIRECT)) {
158 throw new ProtocolException("Relative redirect location '"
159 + uri + "' not allowed");
160 }
161
162 HttpHost target = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
163 if (target == null) {
164 throw new IllegalStateException("Target host not available " +
165 "in the HTTP context");
166 }
167 URI requestURI = new URI(request.getRequestLine().getUri());
168 URI absoluteRequestURI = URIUtils.rewriteURI(requestURI, target, true);
169 uri = URIUtils.resolve(absoluteRequestURI, uri);
170 }
171 } catch (URISyntaxException ex) {
172 throw new ProtocolException(ex.getMessage(), ex);
173 }
174
175 RedirectLocations redirectLocations = (RedirectLocations) context.getAttribute(
176 REDIRECT_LOCATIONS);
177 if (redirectLocations == null) {
178 redirectLocations = new RedirectLocations();
179 context.setAttribute(REDIRECT_LOCATIONS, redirectLocations);
180 }
181 if (params.isParameterFalse(ClientPNames.ALLOW_CIRCULAR_REDIRECTS)) {
182 if (redirectLocations.contains(uri)) {
183 throw new CircularRedirectException("Circular redirect to '" + uri + "'");
184 }
185 }
186 redirectLocations.add(uri);
187 return uri;
188 }
189
190
191
192
193 protected URI createLocationURI(final String location) throws ProtocolException {
194 try {
195 return new URI(location).normalize();
196 } catch (URISyntaxException ex) {
197 throw new ProtocolException("Invalid redirect URI: " + location, ex);
198 }
199 }
200
201
202
203
204 protected boolean isRedirectable(final String method) {
205 for (String m: REDIRECT_METHODS) {
206 if (m.equalsIgnoreCase(method)) {
207 return true;
208 }
209 }
210 return false;
211 }
212
213 public HttpUriRequest getRedirect(
214 final HttpRequest request,
215 final HttpResponse response,
216 final HttpContext context) throws ProtocolException {
217 URI uri = getLocationURI(request, response, context);
218 String method = request.getRequestLine().getMethod();
219 if (method.equalsIgnoreCase(HttpHead.METHOD_NAME)) {
220 return new HttpHead(uri);
221 } else if (method.equalsIgnoreCase(HttpGet.METHOD_NAME)) {
222 return new HttpGet(uri);
223 } else {
224 int status = response.getStatusLine().getStatusCode();
225 if (status == HttpStatus.SC_TEMPORARY_REDIRECT) {
226 if (method.equalsIgnoreCase(HttpPost.METHOD_NAME)) {
227 return copyEntity(new HttpPost(uri), request);
228 } else if (method.equalsIgnoreCase(HttpPut.METHOD_NAME)) {
229 return copyEntity(new HttpPut(uri), request);
230 } else if (method.equalsIgnoreCase(HttpDelete.METHOD_NAME)) {
231 return new HttpDelete(uri);
232 } else if (method.equalsIgnoreCase(HttpTrace.METHOD_NAME)) {
233 return new HttpTrace(uri);
234 } else if (method.equalsIgnoreCase(HttpOptions.METHOD_NAME)) {
235 return new HttpOptions(uri);
236 } else if (method.equalsIgnoreCase(HttpPatch.METHOD_NAME)) {
237 return copyEntity(new HttpPatch(uri), request);
238 }
239 }
240 return new HttpGet(uri);
241 }
242 }
243
244 private HttpUriRequest copyEntity(
245 final HttpEntityEnclosingRequestBase redirect, final HttpRequest original) {
246 if (original instanceof HttpEntityEnclosingRequest) {
247 redirect.setEntity(((HttpEntityEnclosingRequest) original).getEntity());
248 }
249 return redirect;
250 }
251
252 }