svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.plugin / org.gvsig.downloader / org.gvsig.downloader.lib / org.gvsig.downloader.lib.impl / src / main / java / org / gvsig / downloader / lib / impl / SEAuthDownloaderTask.java @ 47843
History | View | Annotate | Download (16.8 KB)
1 |
package org.gvsig.downloader.lib.impl; |
---|---|
2 |
|
3 |
import java.io.File; |
4 |
import java.io.IOException; |
5 |
import java.io.InputStream; |
6 |
import java.net.SocketTimeoutException; |
7 |
import java.net.URL; |
8 |
import java.util.Objects; |
9 |
import java.util.concurrent.Executor; |
10 |
import org.apache.commons.io.IOUtils; |
11 |
import org.apache.commons.lang3.StringUtils; |
12 |
import org.apache.http.Header; |
13 |
import org.apache.http.HttpEntity; |
14 |
import org.apache.http.HttpResponse; |
15 |
import org.apache.http.auth.AuthenticationException; |
16 |
import org.apache.http.client.ClientProtocolException; |
17 |
import org.apache.http.client.ResponseHandler; |
18 |
import org.apache.http.client.config.RequestConfig; |
19 |
import org.apache.http.client.methods.HttpDelete; |
20 |
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; |
21 |
import org.apache.http.client.methods.HttpGet; |
22 |
import org.apache.http.client.methods.HttpPost; |
23 |
import org.apache.http.client.methods.HttpPut; |
24 |
import org.apache.http.client.methods.HttpRequestBase; |
25 |
import org.apache.http.client.methods.HttpUriRequest; |
26 |
import org.apache.http.conn.ConnectTimeoutException; |
27 |
import org.apache.http.entity.ContentType; |
28 |
import org.apache.http.entity.StringEntity; |
29 |
import org.apache.http.impl.client.CloseableHttpClient; |
30 |
import org.apache.http.impl.client.HttpClientBuilder; |
31 |
import org.gvsig.compat.se.net.downloader.se.AbstractSEDownloaderTask; |
32 |
import org.gvsig.compat.se.net.downloader.se.SEDownloader; |
33 |
import org.gvsig.downloader.DownloaderAuthenticationConfig; |
34 |
import org.gvsig.downloader.DownloaderAuthenticationRequester; |
35 |
import org.gvsig.downloader.DownloaderCredentials; |
36 |
import org.gvsig.downloader.DownloaderManager; |
37 |
import org.gvsig.downloader.IOExceptionWithStatus; |
38 |
|
39 |
@SuppressWarnings("UseSpecificCatch") |
40 |
final class SEAuthDownloaderTask |
41 |
extends AbstractSEDownloaderTask
|
42 |
implements Runnable { |
43 |
|
44 |
private class DownloaderResponseHandler implements ResponseHandler<Object> { |
45 |
|
46 |
private int status; |
47 |
private HttpResponse response;
|
48 |
|
49 |
public DownloaderResponseHandler() {
|
50 |
this.status = 0; |
51 |
} |
52 |
|
53 |
@Override
|
54 |
public Object handleResponse(HttpResponse response) throws ClientProtocolException, IOException { |
55 |
this.status=response.getStatusLine().getStatusCode();
|
56 |
this.response = response;
|
57 |
try {
|
58 |
HttpEntity entity = response.getEntity(); |
59 |
if(entity == null) { |
60 |
download(null);
|
61 |
} else {
|
62 |
InputStream content = entity.getContent();
|
63 |
download(content); |
64 |
} |
65 |
|
66 |
} catch (IOExceptionWithStatus ex) {
|
67 |
throw ex;
|
68 |
} catch (Exception ex) { |
69 |
throw new IOExceptionWithStatus(this.status, ex.getLocalizedMessage(), ex); |
70 |
} |
71 |
return null; |
72 |
} |
73 |
|
74 |
public int getStatus() { |
75 |
return this.status; |
76 |
} |
77 |
|
78 |
public String getRedirectionLocation() { |
79 |
try {
|
80 |
Header header = this.response.getFirstHeader("Location"); |
81 |
if(header != null) { |
82 |
return header.getValue();
|
83 |
} |
84 |
} catch (Exception ex) { |
85 |
LOGGER.debug("Can't get redirection location", ex);
|
86 |
} |
87 |
return null; |
88 |
} |
89 |
} |
90 |
|
91 |
public SEAuthDownloaderTask(SEDownloader downloader, URL url, String data, File dstFile, Object groupID) { |
92 |
super(downloader, url, data, dstFile, groupID);
|
93 |
} |
94 |
|
95 |
public SEAuthDownloaderTask(SEDownloader downloader, URL url, String method, ContentType contenttype, String data, File dstFile, Object groupID) { |
96 |
super(downloader, url, method, contenttype, data, dstFile, groupID);
|
97 |
} |
98 |
|
99 |
private DownloaderManagerImpl getDownloader() {
|
100 |
return (DownloaderManagerImpl) this.downloader; |
101 |
} |
102 |
|
103 |
private DownloaderCredentials getCredentials(URL url) { |
104 |
return this.getDownloader().getCredentials(url); |
105 |
} |
106 |
|
107 |
private void addOrReplaceCredentials(DownloaderCredentials credentials) { |
108 |
this.getDownloader().addOrReplaceCredentials(credentials);
|
109 |
} |
110 |
|
111 |
private DownloaderAuthenticationConfig getServiceAuthorizationConfig(URL url) { |
112 |
return this.getDownloader().getAuthenticationConfigurationService(url.toString()); |
113 |
} |
114 |
|
115 |
private void authorize(URL url) { |
116 |
try {
|
117 |
LOGGER.info("AUTHORIZATION REQUIRED");
|
118 |
DownloaderAuthenticationConfig config = this.getServiceAuthorizationConfig(url);
|
119 |
if( config == null ) { |
120 |
config = this.getDownloader().requestAutenticationConfig(url);
|
121 |
if( config == null ) { |
122 |
throw new AuthenticationException("Not service authentication configured for url '"+url+"'."); |
123 |
} |
124 |
} |
125 |
DownloaderAuthenticationRequester authorizationRequester = config.create(); |
126 |
if( authorizationRequester == null ) { |
127 |
throw new AuthenticationException("Can't configure service authentication for url '"+url+"'."); |
128 |
} |
129 |
LOGGER.info("AUTHORIZATION REQUESTER TYPE: "+authorizationRequester.getProviderName());
|
130 |
if( !authorizationRequester.requestAuthorization(this.getExecutorUI()) ) { |
131 |
return;
|
132 |
} |
133 |
DownloaderCredentials credentials = authorizationRequester.getCredentials(); |
134 |
addOrReplaceCredentials(credentials); |
135 |
LOGGER.info("CREDENTIALS: "+credentials.toString());
|
136 |
} catch (Exception ex) { |
137 |
LOGGER.warn("Can't authorize", ex);
|
138 |
} |
139 |
} |
140 |
|
141 |
private DownloaderResponseHandler executeRequest(HttpUriRequest request) throws IOException { |
142 |
|
143 |
int timeout = getTimeout();
|
144 |
RequestConfig requestConfig = RequestConfig.custom() |
145 |
.setConnectTimeout(timeout) |
146 |
.setConnectionRequestTimeout(timeout) |
147 |
.setSocketTimeout(timeout) |
148 |
.build(); |
149 |
URL theUrl = request.getURI().toURL();
|
150 |
CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build(); |
151 |
DownloaderCredentials credentials = this.getCredentials(theUrl);
|
152 |
if (credentials == null || credentials.isAuthorizationTokenExpired()) { |
153 |
DownloaderAuthenticationConfig config = this.getServiceAuthorizationConfig(theUrl);
|
154 |
if( config != null ) { |
155 |
DownloaderAuthenticationRequester authorizationRequester = config.create(); |
156 |
if( authorizationRequester!=null ) { |
157 |
if( authorizationRequester.requestAuthorization(this.getExecutorUI()) ) { |
158 |
credentials = authorizationRequester.getCredentials(); |
159 |
addOrReplaceCredentials(credentials); |
160 |
request.addHeader("Authorization", credentials.getAuthorizationToken());
|
161 |
} |
162 |
} |
163 |
} |
164 |
} else {
|
165 |
request.addHeader("Authorization", credentials.getAuthorizationToken());
|
166 |
} |
167 |
DownloaderResponseHandler responseHandler = new DownloaderResponseHandler();
|
168 |
|
169 |
LOGGER.info("REQUEST "+request.getMethod()+" "+request.getURI().toString()); |
170 |
LOGGER.info("TIMEOUT "+timeout);
|
171 |
for (Header header : request.getAllHeaders()) {
|
172 |
LOGGER.info(header.getName()+": "+header.getValue());
|
173 |
} |
174 |
if( request instanceof HttpEntityEnclosingRequestBase ) { |
175 |
InputStream content = ((HttpEntityEnclosingRequestBase) request).getEntity().getContent();
|
176 |
LOGGER.info("BODY data "+(StringUtils.join(IOUtils.readLines(content,"utf-8"),"\n"))); |
177 |
} |
178 |
LOGGER.info("DOWNLOAD TO "+Objects.toString(dstFile));
|
179 |
try {
|
180 |
httpClient.execute(request,responseHandler); |
181 |
} catch (SocketTimeoutException|ConnectTimeoutException ex) { |
182 |
LOGGER.info("RESPONSE TIMEOUT");
|
183 |
throw ex;
|
184 |
} catch (Exception ex) { |
185 |
LOGGER.info("RESPONSE ERROR "+ex.getLocalizedMessage());
|
186 |
throw ex;
|
187 |
} |
188 |
int status =responseHandler.getStatus();
|
189 |
if(status == 307 || status == 308){ |
190 |
LOGGER.info("RESPONSE LOCATION "+Objects.toString(responseHandler.getRedirectionLocation()));
|
191 |
} |
192 |
LOGGER.info("RESPONSE CODE "+status);
|
193 |
|
194 |
return responseHandler;
|
195 |
} |
196 |
|
197 |
// public File send(String method) throws IOException {
|
198 |
// int status = 500;
|
199 |
// URL theUrl = url;
|
200 |
// try {
|
201 |
// int numretries = 3;
|
202 |
// for (int retries = 0; retries < numretries; retries++) {
|
203 |
// HttpRequestBase request;
|
204 |
// switch (method.toUpperCase()) {
|
205 |
// case METHOD_DELETE:
|
206 |
// request = new HttpDelete(theUrl.toURI());
|
207 |
// break;
|
208 |
// case METHOD_GET:
|
209 |
// default:
|
210 |
// request = new HttpGet(theUrl.toURI());
|
211 |
// break;
|
212 |
// }
|
213 |
//// request.setHeader("User-Agent","Mozilla/5.0 (gvSIG) like Gecko");
|
214 |
// request.setHeader("User-Agent","gvSIG-desktop");
|
215 |
// request.setHeader("Referer","http://www.gvsig.com");
|
216 |
//
|
217 |
// LOGGER.info("RETRY "+retries);
|
218 |
// DownloaderResponseHandler responseHandler = executeRequest(request);
|
219 |
// status = responseHandler.getStatus();
|
220 |
// if(status >= 200 && status < 300) {
|
221 |
// //2xx success
|
222 |
// return this.dstFile;
|
223 |
//
|
224 |
// } else if(status == 307 || status == 308) {
|
225 |
// String redirection = responseHandler.getRedirectionLocation();
|
226 |
// if(StringUtils.isBlank(redirection)) {
|
227 |
// throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status+" redirect to blank URL.");
|
228 |
// }
|
229 |
// try {
|
230 |
// theUrl = new URL(redirection);
|
231 |
// } catch (Exception ex) {
|
232 |
// throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status+" redirect to invalid URL "+redirection);
|
233 |
// }
|
234 |
// } else if(status >= 300 && status < 400) {
|
235 |
// // 3xx redirection
|
236 |
// throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status);
|
237 |
// } else if(status == 401 || status == 403) {
|
238 |
// // "401 Unauthorized" indicates that the request lacks valid authentication credentials
|
239 |
// // "403 Forbidden" the client doesn't have permission to access the requested resource
|
240 |
// // https://www.permit.io/blog/401-vs-403-error-whats-the-difference
|
241 |
// if( retries < numretries-1 ) {
|
242 |
// authorize(theUrl);
|
243 |
// }
|
244 |
// } else if(status >= 400 && status < 500) {
|
245 |
// // 4xx client errors
|
246 |
// throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status);
|
247 |
// } else if(status >= 500 && status < 600) {
|
248 |
// // 5xx server errors
|
249 |
// throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status);
|
250 |
// } else {
|
251 |
// //Unknown
|
252 |
// throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status);
|
253 |
// }
|
254 |
// }
|
255 |
// throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' too many retries, last status " + status);
|
256 |
//
|
257 |
// } catch (IOExceptionWithStatus ex) {
|
258 |
// throw ex;
|
259 |
// } catch (Throwable ex) {
|
260 |
// throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' last status " + status, ex);
|
261 |
// }
|
262 |
// }
|
263 |
|
264 |
private File send(String method, ContentType contentType, String data) throws IOExceptionWithStatus { |
265 |
int status = 500; |
266 |
URL theUrl = url;
|
267 |
try {
|
268 |
int numretries = 3; |
269 |
for (int retries = 0; retries < numretries; retries++) { |
270 |
HttpRequestBase request; |
271 |
switch (method.toUpperCase()) {
|
272 |
case DownloaderManager.METHOD_DELETE:
|
273 |
request = new HttpDelete(theUrl.toURI());
|
274 |
break;
|
275 |
case DownloaderManager.METHOD_PUT:
|
276 |
request = new HttpPut(theUrl.toURI());
|
277 |
request.setHeader("Content-type", contentType.toString());
|
278 |
((HttpPut)request).setEntity(new StringEntity(data, contentType));
|
279 |
break;
|
280 |
case DownloaderManager.METHOD_POST:
|
281 |
request = new HttpPost(theUrl.toURI());
|
282 |
request.setHeader("SOAPAction", "post"); |
283 |
request.setHeader("Content-type", contentType.toString());
|
284 |
((HttpPost)request).setEntity(new StringEntity(data, contentType));
|
285 |
break;
|
286 |
case DownloaderManager.METHOD_GET:
|
287 |
default:
|
288 |
request = new HttpGet(theUrl.toURI());
|
289 |
break;
|
290 |
} |
291 |
// request.setHeader("User-Agent","Mozilla/5.0 (gvSIG) like Gecko");
|
292 |
request.setHeader("User-Agent","gvSIG-desktop"); |
293 |
request.setHeader("Referer","http://www.gvsig.com"); |
294 |
DownloaderResponseHandler responseHandler = executeRequest(request); |
295 |
status = responseHandler.getStatus(); |
296 |
if(status >= 200 && status < 300) { |
297 |
//2xx success
|
298 |
return this.dstFile; |
299 |
|
300 |
} else if(status == 307 || status == 308) { |
301 |
String redirection = responseHandler.getRedirectionLocation();
|
302 |
if(StringUtils.isBlank(redirection)) {
|
303 |
throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status+" redirect to blank URL."); |
304 |
} |
305 |
try {
|
306 |
theUrl = new URL(redirection); |
307 |
} catch (Exception ex) { |
308 |
throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status+" redirect to invalid URL "+redirection); |
309 |
} |
310 |
} else if(status >= 300 && status < 400) { |
311 |
// 3xx redirection
|
312 |
throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status); |
313 |
} else if(status == 401 || status == 403) { |
314 |
// "401 Unauthorized" indicates that the request lacks valid authentication credentials
|
315 |
// "403 Forbidden" the client doesn't have permission to access the requested resource
|
316 |
// https://www.permit.io/blog/401-vs-403-error-whats-the-difference
|
317 |
if( retries < numretries-1 ) { |
318 |
authorize(theUrl); |
319 |
} |
320 |
} else if(status >= 400 && status < 500) { |
321 |
// 4xx client errors
|
322 |
throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status); |
323 |
} else if(status >= 500 && status < 600) { |
324 |
// 5xx server errors
|
325 |
throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status); |
326 |
} else {
|
327 |
//Unknown
|
328 |
throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status); |
329 |
} |
330 |
} |
331 |
throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' too many retries, last status " + status); |
332 |
|
333 |
} catch (IOExceptionWithStatus ex) {
|
334 |
throw ex;
|
335 |
} catch (Throwable ex) { |
336 |
throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' last status " + status, ex); |
337 |
} |
338 |
} |
339 |
|
340 |
|
341 |
|
342 |
@Override
|
343 |
public void run() { |
344 |
try {
|
345 |
send(this.method, this.contenttype, this.data); |
346 |
postdownload(); |
347 |
} catch (Exception e) { |
348 |
exception(e); |
349 |
} |
350 |
} |
351 |
|
352 |
private Executor getExecutorUI() { |
353 |
// return this.downloader.getExecutorUI();
|
354 |
return null; |
355 |
} |
356 |
} |