HTTPProxySocketFactory.java

  1. /**
  2.  *
  3.  * Copyright the original author or authors
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.jivesoftware.smack.proxy;

  18. import java.io.BufferedReader;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.io.StringReader;
  22. import java.net.HttpURLConnection;
  23. import java.net.InetAddress;
  24. import java.net.Socket;
  25. import java.net.UnknownHostException;

  26. import javax.net.SocketFactory;

  27. import org.jivesoftware.smack.util.stringencoder.Base64;

  28. import java.util.regex.Matcher;
  29. import java.util.regex.Pattern;

  30. /**
  31.  * Http Proxy Socket Factory which returns socket connected to Http Proxy
  32.  *
  33.  * @author Atul Aggarwal
  34.  */
  35. class HTTPProxySocketFactory
  36.     extends SocketFactory
  37. {

  38.     private ProxyInfo proxy;

  39.     public HTTPProxySocketFactory(ProxyInfo proxy)
  40.     {
  41.         this.proxy = proxy;
  42.     }

  43.     public Socket createSocket(String host, int port)
  44.         throws IOException, UnknownHostException
  45.     {
  46.         return httpProxifiedSocket(host, port);
  47.     }

  48.     public Socket createSocket(String host ,int port, InetAddress localHost,
  49.                                 int localPort)
  50.         throws IOException, UnknownHostException
  51.     {
  52.         return httpProxifiedSocket(host, port);
  53.     }

  54.     public Socket createSocket(InetAddress host, int port)
  55.         throws IOException
  56.     {
  57.         return httpProxifiedSocket(host.getHostAddress(), port);
  58.        
  59.     }

  60.     public Socket createSocket( InetAddress address, int port,
  61.                                 InetAddress localAddress, int localPort)
  62.         throws IOException
  63.     {
  64.         return httpProxifiedSocket(address.getHostAddress(), port);
  65.     }
  66.  
  67.     private Socket httpProxifiedSocket(String host, int port)
  68.         throws IOException
  69.     {
  70.         String proxyhost = proxy.getProxyAddress();
  71.         int proxyPort = proxy.getProxyPort();
  72.         @SuppressWarnings("resource")
  73.         Socket socket = new Socket(proxyhost,proxyPort);
  74.         String hostport = "CONNECT " + host + ":" + port;
  75.         String proxyLine;
  76.         String username = proxy.getProxyUsername();
  77.         if (username == null)
  78.         {
  79.             proxyLine = "";
  80.         }
  81.         else
  82.         {
  83.             String password = proxy.getProxyPassword();
  84.             proxyLine = "\r\nProxy-Authorization: Basic " + Base64.encode(username + ":" + password);
  85.         }
  86.         socket.getOutputStream().write((hostport + " HTTP/1.1\r\nHost: "
  87.             + hostport + proxyLine + "\r\n\r\n").getBytes("UTF-8"));
  88.        
  89.         InputStream in = socket.getInputStream();
  90.         StringBuilder got = new StringBuilder(100);
  91.         int nlchars = 0;
  92.        
  93.         while (true)
  94.         {
  95.             char c = (char) in.read();
  96.             got.append(c);
  97.             if (got.length() > 1024)
  98.             {
  99.                 throw new ProxyException(ProxyInfo.ProxyType.HTTP, "Recieved " +
  100.                     "header of >1024 characters from "
  101.                     + proxyhost + ", cancelling connection");
  102.             }
  103.             if (c == -1)
  104.             {
  105.                 throw new ProxyException(ProxyInfo.ProxyType.HTTP);
  106.             }
  107.             if ((nlchars == 0 || nlchars == 2) && c == '\r')
  108.             {
  109.                 nlchars++;
  110.             }
  111.             else if ((nlchars == 1 || nlchars == 3) && c == '\n')
  112.             {
  113.                 nlchars++;
  114.             }
  115.             else
  116.             {
  117.                 nlchars = 0;
  118.             }
  119.             if (nlchars == 4)
  120.             {
  121.                 break;
  122.             }
  123.         }

  124.         if (nlchars != 4)
  125.         {
  126.             throw new ProxyException(ProxyInfo.ProxyType.HTTP, "Never " +
  127.                 "received blank line from "
  128.                 + proxyhost + ", cancelling connection");
  129.         }

  130.         String gotstr = got.toString();
  131.        
  132.         BufferedReader br = new BufferedReader(new StringReader(gotstr));
  133.         String response = br.readLine();
  134.        
  135.         if (response == null)
  136.         {
  137.             throw new ProxyException(ProxyInfo.ProxyType.HTTP, "Empty proxy " +
  138.                 "response from " + proxyhost + ", cancelling");
  139.         }
  140.        
  141.         Matcher m = RESPONSE_PATTERN.matcher(response);
  142.         if (!m.matches())
  143.         {
  144.             throw new ProxyException(ProxyInfo.ProxyType.HTTP , "Unexpected " +
  145.                 "proxy response from " + proxyhost + ": " + response);
  146.         }
  147.        
  148.         int code = Integer.parseInt(m.group(1));
  149.        
  150.         if (code != HttpURLConnection.HTTP_OK)
  151.         {
  152.             throw new ProxyException(ProxyInfo.ProxyType.HTTP);
  153.         }
  154.        
  155.         return socket;
  156.     }

  157.     private static final Pattern RESPONSE_PATTERN
  158.         = Pattern.compile("HTTP/\\S+\\s(\\d+)\\s(.*)\\s*");

  159. }