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