source: 3thparty/jupload/src/main/java/wjhk/jupload2/upload/helper/HttpConnect.java @ 3951

Revision 3951, 14.9 KB checked in by alexandrecorreia, 13 years ago (diff)

Ticket #1709 - Adicao de codigo fonte java do componente jupload

Line 
1//
2// $Id: HttpConnect.java 286 2007-06-17 09:03:29 +0000 (dim., 17 juin 2007)
3// felfert $
4//
5// jupload - A file upload applet.
6//
7// Copyright 2007 The JUpload Team
8//
9// Created: 07.05.2007
10// Creator: felfert
11// Last modified: $Date: 2010-09-20 09:14:51 -0300 (Seg, 20 Set 2010) $
12//
13// This program is free software; you can redistribute it and/or modify
14// it under the terms of the GNU General Public License as published by
15// the Free Software Foundation; either version 2 of the License, or
16// (at your option) any later version.
17//
18// This program is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21// GNU General Public License for more details.
22//
23// You should have received a copy of the GNU General Public License
24// along with this program; if not, write to the Free Software
25// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
27package wjhk.jupload2.upload.helper;
28
29import java.io.IOException;
30import java.net.ConnectException;
31import java.net.InetSocketAddress;
32import java.net.Proxy;
33import java.net.ProxySelector;
34import java.net.Socket;
35import java.net.URISyntaxException;
36import java.net.URL;
37import java.net.UnknownHostException;
38import java.security.KeyManagementException;
39import java.security.KeyStoreException;
40import java.security.NoSuchAlgorithmException;
41import java.security.UnrecoverableKeyException;
42import java.security.cert.CertificateException;
43import java.util.regex.Matcher;
44import java.util.regex.Pattern;
45
46import javax.net.ssl.SSLContext;
47
48import wjhk.jupload2.exception.JUploadException;
49import wjhk.jupload2.policies.UploadPolicy;
50import javax.net.ssl.X509TrustManager;
51
52import java.security.cert.X509Certificate;
53
54import java.io.InputStreamReader;
55import java.io.OutputStreamWriter;
56import java.io.BufferedReader;
57import java.io.BufferedWriter;
58
59/**
60 * This class implements the task of connecting to a HTTP(S) url using a proxy.
61 *
62 * @author felfert
63 */
64public class HttpConnect {
65
66        // TrustManager to allow all certificates
67        private final class TM implements X509TrustManager {
68                public void checkClientTrusted(X509Certificate[] arg0, String arg1)
69                                throws CertificateException {
70                }
71
72                public void checkServerTrusted(X509Certificate[] chain, String authType)
73                                throws CertificateException {
74                }
75
76                public X509Certificate[] getAcceptedIssuers() {
77                        return new X509Certificate[0];
78                }
79        }
80
81        private final static String HTTPCONNECT_DEFAULT_PROTOCOL = "HTTP/1.1";
82
83        /**
84         * The current upload policy. Used for logging, and to get the post URL.
85         * Also used to change this URL, when it has moved (301, 302 or 303 return
86         * code)
87         */
88        private UploadPolicy uploadPolicy;
89
90        /**
91         * Connects to a given URL.
92         *
93         * @param url
94         *            The URL to connect to
95         * @param proxy
96         *            The proxy to be used, may be null if direct connection is
97         *            needed
98         * @return A socket, connected to the specified URL. May be null if an error
99         *         occurs.
100         * @throws NoSuchAlgorithmException
101         * @throws KeyManagementException
102         * @throws IOException
103         * @throws UnknownHostException
104         * @throws ConnectException
105         * @throws CertificateException
106         * @throws KeyStoreException
107         * @throws UnrecoverableKeyException
108         * @throws IllegalArgumentException
109         */
110        public Socket connect(URL url, Proxy proxy)
111                        throws NoSuchAlgorithmException, KeyManagementException,
112                        ConnectException, UnknownHostException, IOException,
113                        KeyStoreException, CertificateException, IllegalArgumentException,
114                        UnrecoverableKeyException {
115                // Temporary socket for SOCKS support
116                Socket tsock;
117                Socket ret = null;
118                String host = url.getHost();
119                int port;
120                boolean useProxy = ((proxy != null) && (proxy.type() != Proxy.Type.DIRECT));
121
122                // Check if SSL connection is needed
123                if (url.getProtocol().equals("https")) {
124                        port = (-1 == url.getPort()) ? 443 : url.getPort();
125                        SSLContext context = SSLContext.getInstance("SSL");
126                        // Allow all certificates
127                        context.init(null, new X509TrustManager[] { new TM() }, null);
128                        if (useProxy) {
129                                if (proxy.type() == Proxy.Type.HTTP) {
130                                        // First establish a CONNECT, then do a normal SSL
131                                        // thru that connection.
132                                       
133                                        //Patch given by cuspy (Patch 3043476 on Sourceforge)
134                                        BufferedWriter writer;
135                                        BufferedReader reader;
136                                        String proxyhost;
137                                        int proxyport;
138                                        InetSocketAddress sa = (InetSocketAddress) proxy.address();
139                                        proxyhost = (sa.isUnresolved()) ? sa.getHostName() : sa
140                                                        .getAddress().getHostAddress();
141                                        proxyport = sa.getPort();
142                                        this.uploadPolicy.displayDebug(
143                                                        "Using SSL socket, via HTTP proxy", 20);
144                                        tsock = new Socket(proxyhost, proxyport);
145                                        writer = new BufferedWriter(new OutputStreamWriter(tsock
146                                                        .getOutputStream()));
147                                        reader = new BufferedReader(new InputStreamReader(tsock
148                                                        .getInputStream()));
149                                        String hostport = host + ":" + port;
150                                        String req = "CONNECT " + hostport + " HTTP/1.0\r\n\r\n";
151                                        writer.write(req);
152                                        writer.flush();
153                                        String res = reader.readLine();
154                                        String[] status = res.split(" ", 3);
155                                        if(status.length < 2 || !status[1].startsWith("200")) {
156                        this.uploadPolicy.displayDebug("res: " + res, 10);
157                                                throw new ConnectException("proxy connection error");
158                                        }
159                                        ret = context.getSocketFactory().createSocket(tsock,
160                                                        url.getHost(), port, true);
161                                } else if (proxy.type() == Proxy.Type.SOCKS) {
162                                        this.uploadPolicy.displayDebug(
163                                                        "Using SSL socket, via SOCKS proxy", 20);
164                                        tsock = new Socket(proxy);
165                                        tsock.connect(new InetSocketAddress(host, port));
166                                        ret = context.getSocketFactory().createSocket(tsock, host,
167                                                        port, true);
168
169                                } else
170                                        throw new ConnectException("Unkown proxy type "
171                                                        + proxy.type());
172                        } else {
173                                // If port not specified then use default https port
174                                // 443.
175                                this.uploadPolicy.displayDebug(
176                                                "Using SSL socket, direct connection", 20);
177                                ret = context.getSocketFactory().createSocket(host, port);
178                        }
179                } else {
180                        // If we are not in SSL, just use the old code.
181                        port = (-1 == url.getPort()) ? 80 : url.getPort();
182                        if (useProxy) {
183                                if (proxy.type() == Proxy.Type.HTTP) {
184                                        InetSocketAddress sa = (InetSocketAddress) proxy.address();
185                                        host = (sa.isUnresolved()) ? sa.getHostName() : sa
186                                                        .getAddress().getHostAddress();
187                                        port = sa.getPort();
188                                        this.uploadPolicy.displayDebug(
189                                                        "Using non SSL socket, proxy=" + host + ":" + port,
190                                                        20);
191                                        ret = new Socket(host, port);
192                                } else if (proxy.type() == Proxy.Type.SOCKS) {
193                                        this.uploadPolicy.displayDebug(
194                                                        "Using non SSL socket, via SOCKS proxy", 20);
195                                        tsock = new Socket(proxy);
196                                        tsock.connect(new InetSocketAddress(host, port));
197                                        ret = tsock;
198                                } else
199                                        throw new ConnectException("Unkown proxy type "
200                                                        + proxy.type());
201                        } else {
202                                this.uploadPolicy.displayDebug(
203                                                "Using non SSL socket, direct connection", 20);
204                                ret = new Socket(host, port);
205                        }
206                }
207                return ret;
208        }
209
210        /**
211         * Connects to a given URL automatically using a proxy.
212         *
213         * @param url
214         *            The URL to connect to
215         * @return A socket, connected to the specified URL. May be null if an error
216         *         occurs.
217         * @throws NoSuchAlgorithmException
218         * @throws KeyManagementException
219         * @throws IOException
220         * @throws UnknownHostException
221         * @throws ConnectException
222         * @throws URISyntaxException
223         * @throws UnrecoverableKeyException
224         * @throws CertificateException
225         * @throws KeyStoreException
226         * @throws UnrecoverableKeyException
227         * @throws IllegalArgumentException
228         */
229        public Socket connect(URL url) throws NoSuchAlgorithmException,
230                        KeyManagementException, ConnectException, UnknownHostException,
231                        IOException, URISyntaxException, KeyStoreException,
232                        CertificateException, IllegalArgumentException,
233                        UnrecoverableKeyException {
234                Proxy proxy = ProxySelector.getDefault().select(url.toURI()).get(0);
235                return connect(url, proxy);
236        }
237
238        /**
239         * Retrieve the protocol to be used for the postURL of the current policy.
240         * This method issues a HEAD request to the postURL and then examines the
241         * protocol version returned in the response.
242         *
243         * @return The string, describing the protocol (e.g. "HTTP/1.1")
244         * @throws URISyntaxException
245         * @throws IOException
246         * @throws UnrecoverableKeyException
247         * @throws IllegalArgumentException
248         * @throws CertificateException
249         * @throws KeyStoreException
250         * @throws UnknownHostException
251         * @throws NoSuchAlgorithmException
252         * @throws KeyManagementException
253         * @throws JUploadException
254         */
255        public String getProtocol() throws URISyntaxException,
256                        KeyManagementException, NoSuchAlgorithmException,
257                        UnknownHostException, KeyStoreException, CertificateException,
258                        IllegalArgumentException, UnrecoverableKeyException, IOException,
259                        JUploadException {
260
261                String protocol = HTTPCONNECT_DEFAULT_PROTOCOL;
262                URL url = new URL(this.uploadPolicy.getPostURL());
263                this.uploadPolicy
264                                .displayDebug("Checking protocol with URL: " + url, 30);
265                HTTPConnectionHelper connectionHelper = new HTTPConnectionHelper(url,
266                                "HEAD", false, true, this.uploadPolicy);
267                connectionHelper.append("\r\n");
268                this.uploadPolicy.displayDebug("Before sendRequest()", 30);
269                connectionHelper.sendRequest();
270                this.uploadPolicy.displayDebug("After sendRequest()", 30);
271                connectionHelper.getOutputStream().flush();
272                if (this.uploadPolicy.getDebugLevel() >= 80) {
273                        this.uploadPolicy
274                                        .displayDebug(
275                                                        "-------------------------------------------------------------------------",
276                                                        80);
277                        this.uploadPolicy
278                                        .displayDebug(
279                                                        "-----------------   HEAD message sent (start)  --------------------------",
280                                                        80);
281                        this.uploadPolicy
282                                        .displayDebug(
283                                                        "-------------------------------------------------------------------------",
284                                                        80);
285                        this.uploadPolicy.displayDebug(connectionHelper
286                                        .getByteArrayEncoder().getString(), 80);
287                        this.uploadPolicy
288                                        .displayDebug(
289                                                        "-------------------------------------------------------------------------",
290                                                        80);
291                        this.uploadPolicy
292                                        .displayDebug(
293                                                        "-----------------   HEAD message sent (end) -----------------------------",
294                                                        80);
295                        this.uploadPolicy
296                                        .displayDebug(
297                                                        "-------------------------------------------------------------------------",
298                                                        80);
299                }
300
301                int status = connectionHelper.readHttpResponse();
302                this.uploadPolicy.displayDebug("HEAD status: " + status, 30);
303                String headers = connectionHelper.getResponseHeaders();
304
305                // Let's look for the protocol
306                Matcher m = Pattern.compile("^(HTTP/\\d\\.\\d)\\s(.*)\\s.*$",
307                                Pattern.MULTILINE).matcher(headers);
308                if (!m.find()) {
309                        // Using default value. Already initialized.
310                        this.uploadPolicy
311                                        .displayErr("Unexpected HEAD response (can't find the protocol): will use the default one.");
312                } else {
313                        // We will return the found protocol.
314                        protocol = m.group(1);
315                        this.uploadPolicy.displayDebug("HEAD protocol: " + protocol, 30);
316                }
317
318                // Let's check if we're facing an IIS server. The applet is compatible
319                // with IIS, only if allowHttpPersistent is false.
320                Pattern pIIS = Pattern.compile("^Server: .*IIS*$", Pattern.MULTILINE);
321                Matcher mIIS = pIIS.matcher(headers);
322                if (mIIS.find()) {
323                        try {
324                                this.uploadPolicy.setProperty(
325                                                UploadPolicy.PROP_ALLOW_HTTP_PERSISTENT, "false");
326                                this.uploadPolicy
327                                                .displayWarn(UploadPolicy.PROP_ALLOW_HTTP_PERSISTENT
328                                                                + "' forced to false, for IIS compatibility (in HttpConnect.getProtocol())");
329                        } catch (JUploadException e) {
330                                this.uploadPolicy.displayWarn("Can't set property '"
331                                                + UploadPolicy.PROP_ALLOW_HTTP_PERSISTENT
332                                                + "' to false, in HttpConnect.getProtocol()");
333                        }
334                }
335
336                // if we got a redirection code, we must find the new Location.
337                if (status == 301 || status == 302 || status == 303) {
338                        Pattern pLocation = Pattern.compile("^Location: (.*)$",
339                                        Pattern.MULTILINE);
340                        Matcher mLocation = pLocation.matcher(headers);
341                        if (mLocation.find()) {
342                                // We found the location where we should go instead of the
343                                // original postURL
344                                this.uploadPolicy.displayDebug("Location read: "
345                                                + mLocation.group(1), 50);
346                                changePostURL(mLocation.group(1));
347                        }
348                }
349
350                // Let's free any used resource.
351                connectionHelper.dispose();
352
353                return protocol;
354        } // getProtocol()
355
356        /**
357         * Reaction of the applet when a 301, 302 et 303 return code is returned.
358         * The postURL is changed according to the Location header returned.
359         *
360         * @param newLocation
361         *            This new location may contain the http://host.name.domain part
362         *            of the URL ... or not
363         */
364        private void changePostURL(String newLocation) throws JUploadException {
365                String currentPostURL = this.uploadPolicy.getPostURL();
366                String newPostURL;
367                Pattern pHostName = Pattern.compile("http://([^/]*)/.*");
368                Matcher mOldPostURL = Pattern.compile("(.*)\\?(.*)").matcher(
369                                currentPostURL);
370
371                // If there is an interrogation point in the original postURL, we'll
372                // keep the parameters, and just changed the URI part.
373                if (mOldPostURL.matches()) {
374                        newPostURL = newLocation + '?' + mOldPostURL.group(2);
375                        // Otherwise, we change the whole URL.
376                } else {
377                        newPostURL = newLocation;
378                }
379
380                // There are three main cases or newLocation:
381                // 1- It's a full URL, with host name...
382                // 2- It's a local full path on the same server (begins with /)
383                // 3- It's a relative path (for instance, add of a prefix in the
384                // filename) (doesn't begin with /)
385                Matcher mHostOldPostURL = pHostName.matcher(currentPostURL);
386                if (!mHostOldPostURL.matches()) {
387                        // Oups ! There is a little trouble here !
388                        throw new JUploadException(
389                                        "[HttpConnect.changePostURL()] No host found in the old postURL !");
390                }
391
392                // Let's analyze the given newLocation for these three cases.
393                Matcher mHostNewLocation = pHostName.matcher(newLocation);
394                if (mHostNewLocation.matches()) {
395                        // 1- It's a full URL, with host name. We already got this URL, in
396                        // the newPostURL initialization.
397                } else if (newLocation.startsWith("/")) {
398                        // 2- It's a local full path on the same server (begins with /)
399                        newPostURL = "http://" + mHostOldPostURL.group(1) + newPostURL;
400                } else {
401                        // 3- It's a relative path (for instance, add of a prefix in the
402                        // filename) (doesn't begin with /)
403                        Matcher mOldPostURLAllButFilename = Pattern
404                                        .compile("(.*)/([^/]*)$").matcher(currentPostURL);
405                        if (!mOldPostURLAllButFilename.matches()) {
406                                // Hum, that won't be easy.
407                                throw new JUploadException(
408                                                "[HttpConnect.changePostURL()] Can't find the filename in the URL !");
409                        }
410                        newPostURL = mOldPostURLAllButFilename.group(1) + "/" + newPostURL;
411                }
412
413                // Let's store this new postURL, and display some info about the change
414                this.uploadPolicy.setPostURL(newPostURL);
415                this.uploadPolicy.displayInfo("postURL switched from " + currentPostURL
416                                + " to " + newPostURL);
417        }
418
419        /**
420         * Creates a new instance.
421         *
422         * @param policy
423         *            The UploadPolicy to be used for logging.
424         */
425        public HttpConnect(UploadPolicy policy) {
426                this.uploadPolicy = policy;
427        }
428}
Note: See TracBrowser for help on using the repository browser.