blob: 4ee5dd622b6ed9f1a64e27f1c71cc36035419610 [file] [log] [blame]
Shuyi Chend7955ce2013-05-22 14:51:55 -07001/**
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 */
18package org.jivesoftware.smack.proxy;
19
20import java.io.BufferedReader;
21import java.io.IOException;
22import java.io.InputStream;
23import java.io.StringReader;
24import java.net.HttpURLConnection;
25import java.net.InetAddress;
26import java.net.Socket;
27import java.net.UnknownHostException;
28import javax.net.SocketFactory;
29import org.jivesoftware.smack.util.StringUtils;
30
31import java.util.regex.Matcher;
32import java.util.regex.Pattern;
33
34/**
35 * Http Proxy Socket Factory which returns socket connected to Http Proxy
36 *
37 * @author Atul Aggarwal
38 */
39class 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}