Statistics
| Revision:

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
}