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