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