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 import java.util.Arrays;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.apache.http.Header;
37 import org.apache.http.HttpHost;
38 import org.apache.http.HttpRequest;
39 import org.apache.http.HttpResponse;
40 import org.apache.http.HttpStatus;
41 import org.apache.http.ProtocolException;
42 import org.apache.http.annotation.Contract;
43 import org.apache.http.annotation.ThreadingBehavior;
44 import org.apache.http.client.CircularRedirectException;
45 import org.apache.http.client.RedirectStrategy;
46 import org.apache.http.client.config.RequestConfig;
47 import org.apache.http.client.methods.HttpGet;
48 import org.apache.http.client.methods.HttpHead;
49 import org.apache.http.client.methods.HttpUriRequest;
50 import org.apache.http.client.methods.RequestBuilder;
51 import org.apache.http.client.protocol.HttpClientContext;
52 import org.apache.http.client.utils.URIUtils;
53 import org.apache.http.protocol.HttpContext;
54 import org.apache.http.util.Args;
55 import org.apache.http.util.Asserts;
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 @Contract(threading = ThreadingBehavior.IMMUTABLE)
73 public class DefaultRedirectStrategy implements RedirectStrategy {
74
75 private final Log log = LogFactory.getLog(getClass());
76
77 public static final int SC_PERMANENT_REDIRECT = 308;
78
79
80
81
82 @Deprecated
83 public static final String REDIRECT_LOCATIONS = "http.protocol.redirect-locations";
84
85 public static final DefaultRedirectStrategytrategy.html#DefaultRedirectStrategy">DefaultRedirectStrategy INSTANCE = new DefaultRedirectStrategy();
86
87 private final String[] redirectMethods;
88
89 public DefaultRedirectStrategy() {
90 this(new String[] {
91 HttpGet.METHOD_NAME,
92 HttpHead.METHOD_NAME
93 });
94 }
95
96
97
98
99
100
101
102 public DefaultRedirectStrategy(final String[] redirectMethods) {
103 super();
104 final String[] tmp = redirectMethods.clone();
105 Arrays.sort(tmp);
106 this.redirectMethods = tmp;
107 }
108
109 @Override
110 public boolean isRedirected(
111 final HttpRequest request,
112 final HttpResponse response,
113 final HttpContext context) throws ProtocolException {
114 Args.notNull(request, "HTTP request");
115 Args.notNull(response, "HTTP response");
116
117 final int statusCode = response.getStatusLine().getStatusCode();
118 final String method = request.getRequestLine().getMethod();
119 final Header locationHeader = response.getFirstHeader("location");
120 switch (statusCode) {
121 case HttpStatus.SC_MOVED_TEMPORARILY:
122 return isRedirectable(method) && locationHeader != null;
123 case HttpStatus.SC_MOVED_PERMANENTLY:
124 case HttpStatus.SC_TEMPORARY_REDIRECT:
125 case SC_PERMANENT_REDIRECT:
126 return isRedirectable(method);
127 case HttpStatus.SC_SEE_OTHER:
128 return true;
129 default:
130 return false;
131 }
132 }
133
134 public URI getLocationURI(
135 final HttpRequest request,
136 final HttpResponse response,
137 final HttpContext context) throws ProtocolException {
138 Args.notNull(request, "HTTP request");
139 Args.notNull(response, "HTTP response");
140 Args.notNull(context, "HTTP context");
141
142 final HttpClientContext clientContext = HttpClientContext.adapt(context);
143
144
145 final Header locationHeader = response.getFirstHeader("location");
146 if (locationHeader == null) {
147
148 throw new ProtocolException(
149 "Received redirect response " + response.getStatusLine()
150 + " but no location header");
151 }
152 final String location = locationHeader.getValue();
153 if (this.log.isDebugEnabled()) {
154 this.log.debug("Redirect requested to location '" + location + "'");
155 }
156
157 final RequestConfig config = clientContext.getRequestConfig();
158
159 URI uri = createLocationURI(location);
160
161 try {
162 if (config.isNormalizeUri()) {
163 uri = URIUtils.normalizeSyntax(uri);
164 }
165
166
167
168 if (!uri.isAbsolute()) {
169 if (!config.isRelativeRedirectsAllowed()) {
170 throw new ProtocolException("Relative redirect location '"
171 + uri + "' not allowed");
172 }
173
174 final HttpHost target = clientContext.getTargetHost();
175 Asserts.notNull(target, "Target host");
176 final URI requestURI = new URI(request.getRequestLine().getUri());
177 final URI absoluteRequestURI = URIUtils.rewriteURI(requestURI, target,
178 config.isNormalizeUri() ? URIUtils.NORMALIZE : URIUtils.NO_FLAGS);
179 uri = URIUtils.resolve(absoluteRequestURI, uri);
180 }
181 } catch (final URISyntaxException ex) {
182 throw new ProtocolException(ex.getMessage(), ex);
183 }
184
185 RedirectLocationsche/http/impl/client/RedirectLocations.html#RedirectLocations">RedirectLocations redirectLocations = (RedirectLocations) clientContext.getAttribute(
186 HttpClientContext.REDIRECT_LOCATIONS);
187 if (redirectLocations == null) {
188 redirectLocations = new RedirectLocations();
189 context.setAttribute(HttpClientContext.REDIRECT_LOCATIONS, redirectLocations);
190 }
191 if (!config.isCircularRedirectsAllowed()) {
192 if (redirectLocations.contains(uri)) {
193 throw new CircularRedirectException("Circular redirect to '" + uri + "'");
194 }
195 }
196 redirectLocations.add(uri);
197 return uri;
198 }
199
200
201
202
203 protected URI createLocationURI(final String location) throws ProtocolException {
204 try {
205 return new URI(location);
206 } catch (final URISyntaxException ex) {
207 throw new ProtocolException("Invalid redirect URI: " + location, ex);
208 }
209 }
210
211
212
213
214 protected boolean isRedirectable(final String method) {
215 return Arrays.binarySearch(redirectMethods, method) >= 0;
216 }
217
218 @Override
219 public HttpUriRequest getRedirect(
220 final HttpRequest request,
221 final HttpResponse response,
222 final HttpContext context) throws ProtocolException {
223 final URI uri = getLocationURI(request, response, context);
224 final String method = request.getRequestLine().getMethod();
225 if (method.equalsIgnoreCase(HttpHead.METHOD_NAME)) {
226 return new HttpHead(uri);
227 } else if (method.equalsIgnoreCase(HttpGet.METHOD_NAME)) {
228 return new HttpGet(uri);
229 } else {
230 final int status = response.getStatusLine().getStatusCode();
231 return (status == HttpStatus.SC_TEMPORARY_REDIRECT || status == SC_PERMANENT_REDIRECT)
232 ? RequestBuilder.copy(request).setUri(uri).build()
233 : new HttpGet(uri);
234 }
235 }
236
237 }