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 @ 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
}