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