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