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