Home | History | Annotate | Download | only in proxy
      1 /**
      2  * $RCSfile$
      3  * $Revision$
      4  * $Date$
      5  *
      6  * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  */
     18 package org.jivesoftware.smack.proxy;
     19 
     20 import java.io.BufferedReader;
     21 import java.io.IOException;
     22 import java.io.InputStream;
     23 import java.io.StringReader;
     24 import java.net.HttpURLConnection;
     25 import java.net.InetAddress;
     26 import java.net.Socket;
     27 import java.net.UnknownHostException;
     28 import javax.net.SocketFactory;
     29 import org.jivesoftware.smack.util.StringUtils;
     30 
     31 import java.util.regex.Matcher;
     32 import java.util.regex.Pattern;
     33 
     34 /**
     35  * Http Proxy Socket Factory which returns socket connected to Http Proxy
     36  *
     37  * @author Atul Aggarwal
     38  */
     39 class HTTPProxySocketFactory
     40     extends SocketFactory
     41 {
     42 
     43     private ProxyInfo proxy;
     44 
     45     public HTTPProxySocketFactory(ProxyInfo proxy)
     46     {
     47         this.proxy = proxy;
     48     }
     49 
     50     public Socket createSocket(String host, int port)
     51         throws IOException, UnknownHostException
     52     {
     53         return httpProxifiedSocket(host, port);
     54     }
     55 
     56     public Socket createSocket(String host ,int port, InetAddress localHost,
     57                                 int localPort)
     58         throws IOException, UnknownHostException
     59     {
     60         return httpProxifiedSocket(host, port);
     61     }
     62 
     63     public Socket createSocket(InetAddress host, int port)
     64         throws IOException
     65     {
     66         return httpProxifiedSocket(host.getHostAddress(), port);
     67 
     68     }
     69 
     70     public Socket createSocket( InetAddress address, int port,
     71                                 InetAddress localAddress, int localPort)
     72         throws IOException
     73     {
     74         return httpProxifiedSocket(address.getHostAddress(), port);
     75     }
     76 
     77     private Socket httpProxifiedSocket(String host, int port)
     78         throws IOException
     79     {
     80         String proxyhost = proxy.getProxyAddress();
     81         int proxyPort = proxy.getProxyPort();
     82         Socket socket = new Socket(proxyhost,proxyPort);
     83         String hostport = "CONNECT " + host + ":" + port;
     84         String proxyLine;
     85         String username = proxy.getProxyUsername();
     86         if (username == null)
     87         {
     88             proxyLine = "";
     89         }
     90         else
     91         {
     92             String password = proxy.getProxyPassword();
     93             proxyLine = "\r\nProxy-Authorization: Basic " + StringUtils.encodeBase64(username + ":" + password);
     94         }
     95         socket.getOutputStream().write((hostport + " HTTP/1.1\r\nHost: "
     96             + hostport + proxyLine + "\r\n\r\n").getBytes("UTF-8"));
     97 
     98         InputStream in = socket.getInputStream();
     99         StringBuilder got = new StringBuilder(100);
    100         int nlchars = 0;
    101 
    102         while (true)
    103         {
    104             char c = (char) in.read();
    105             got.append(c);
    106             if (got.length() > 1024)
    107             {
    108                 throw new ProxyException(ProxyInfo.ProxyType.HTTP, "Recieved " +
    109                     "header of >1024 characters from "
    110                     + proxyhost + ", cancelling connection");
    111             }
    112             if (c == -1)
    113             {
    114                 throw new ProxyException(ProxyInfo.ProxyType.HTTP);
    115             }
    116             if ((nlchars == 0 || nlchars == 2) && c == '\r')
    117             {
    118                 nlchars++;
    119             }
    120             else if ((nlchars == 1 || nlchars == 3) && c == '\n')
    121             {
    122                 nlchars++;
    123             }
    124             else
    125             {
    126                 nlchars = 0;
    127             }
    128             if (nlchars == 4)
    129             {
    130                 break;
    131             }
    132         }
    133 
    134         if (nlchars != 4)
    135         {
    136             throw new ProxyException(ProxyInfo.ProxyType.HTTP, "Never " +
    137                 "received blank line from "
    138                 + proxyhost + ", cancelling connection");
    139         }
    140 
    141         String gotstr = got.toString();
    142 
    143         BufferedReader br = new BufferedReader(new StringReader(gotstr));
    144         String response = br.readLine();
    145 
    146         if (response == null)
    147         {
    148             throw new ProxyException(ProxyInfo.ProxyType.HTTP, "Empty proxy " +
    149                 "response from " + proxyhost + ", cancelling");
    150         }
    151 
    152         Matcher m = RESPONSE_PATTERN.matcher(response);
    153         if (!m.matches())
    154         {
    155             throw new ProxyException(ProxyInfo.ProxyType.HTTP , "Unexpected " +
    156                 "proxy response from " + proxyhost + ": " + response);
    157         }
    158 
    159         int code = Integer.parseInt(m.group(1));
    160 
    161         if (code != HttpURLConnection.HTTP_OK)
    162         {
    163             throw new ProxyException(ProxyInfo.ProxyType.HTTP);
    164         }
    165 
    166         return socket;
    167     }
    168 
    169     private static final Pattern RESPONSE_PATTERN
    170         = Pattern.compile("HTTP/\\S+\\s(\\d+)\\s(.*)\\s*");
    171 
    172 }
    173