273
|
1 package ch.ethz.ssh2.transport;
|
|
2
|
|
3 import java.io.IOException;
|
|
4 import java.io.InputStream;
|
|
5 import java.io.InputStreamReader;
|
|
6 import java.io.LineNumberReader;
|
|
7 import java.io.OutputStream;
|
|
8 import java.net.InetSocketAddress;
|
|
9 import java.net.Socket;
|
|
10
|
|
11 import ch.ethz.ssh2.HTTPProxyData;
|
|
12 import ch.ethz.ssh2.HTTPProxyException;
|
|
13 import ch.ethz.ssh2.crypto.Base64;
|
|
14 import ch.ethz.ssh2.util.StringEncoder;
|
|
15
|
|
16 /**
|
|
17 * @version $Id: HTTPProxyClientTransportManager.java 155 2014-04-28 12:01:19Z dkocher@sudo.ch $
|
|
18 */
|
|
19 public class HTTPProxyClientTransportManager extends ClientTransportManager {
|
|
20
|
|
21 /**
|
|
22 * Used to tell the library that the connection shall be established through a proxy server.
|
|
23 */
|
|
24
|
|
25 private HTTPProxyData pd;
|
|
26
|
|
27 private final Socket sock;
|
|
28
|
|
29 public HTTPProxyClientTransportManager(final Socket socket, final HTTPProxyData pd) {
|
|
30 super(socket);
|
|
31 this.sock = socket;
|
|
32 this.pd = pd;
|
|
33 }
|
|
34
|
|
35 @Override
|
|
36 protected void connect(final String hostname, final int port, final int connectTimeout) throws IOException {
|
|
37 sock.connect(new InetSocketAddress(pd.proxyHost, pd.proxyPort), connectTimeout);
|
|
38 // Tell the proxy where we actually want to connect to
|
|
39 StringBuilder sb = new StringBuilder();
|
|
40 sb.append("CONNECT ");
|
|
41 sb.append(hostname);
|
|
42 sb.append(':');
|
|
43 sb.append(port);
|
|
44 sb.append(" HTTP/1.0\r\n");
|
|
45
|
307
|
46 if ((pd.proxyUser != null) && (pd.proxyPass != null)) {
|
273
|
47 String credentials = pd.proxyUser + ":" + pd.proxyPass;
|
|
48 char[] encoded = Base64.encode(StringEncoder.GetBytes(credentials));
|
|
49 sb.append("Proxy-Authorization: Basic ");
|
|
50 sb.append(encoded);
|
|
51 sb.append("\r\n");
|
|
52 }
|
|
53
|
307
|
54 if (pd.requestHeaderLines != null) {
|
|
55 for (int i = 0; i < pd.requestHeaderLines.length; i++) {
|
|
56 if (pd.requestHeaderLines[i] != null) {
|
273
|
57 sb.append(pd.requestHeaderLines[i]);
|
|
58 sb.append("\r\n");
|
|
59 }
|
|
60 }
|
|
61 }
|
|
62
|
|
63 sb.append("\r\n");
|
|
64 OutputStream out = sock.getOutputStream();
|
|
65 out.write(StringEncoder.GetBytes(sb.toString()));
|
|
66 out.flush();
|
|
67 // Parse the HTTP response
|
|
68 InputStream in = sock.getInputStream();
|
|
69 final LineNumberReader reader = new LineNumberReader(new InputStreamReader(in));
|
|
70 String httpReponse = reader.readLine();
|
|
71
|
307
|
72 if (!httpReponse.startsWith("HTTP/")) {
|
273
|
73 throw new IOException("The proxy did not send back a valid HTTP response.");
|
|
74 }
|
|
75
|
|
76 // "HTTP/1.X XYZ X" => 14 characters minimum
|
|
77
|
307
|
78 if ((httpReponse.length() < 14) || (httpReponse.charAt(8) != ' ') || (httpReponse.charAt(12) != ' ')) {
|
273
|
79 throw new IOException("The proxy did not send back a valid HTTP response.");
|
|
80 }
|
|
81
|
|
82 int errorCode;
|
|
83
|
|
84 try {
|
|
85 errorCode = Integer.parseInt(httpReponse.substring(9, 12));
|
|
86 }
|
307
|
87 catch (NumberFormatException ignore) {
|
273
|
88 throw new IOException("The proxy did not send back a valid HTTP response.");
|
|
89 }
|
|
90
|
307
|
91 if ((errorCode < 0) || (errorCode > 999)) {
|
273
|
92 throw new IOException("The proxy did not send back a valid HTTP response.");
|
|
93 }
|
|
94
|
307
|
95 if (errorCode != 200) {
|
273
|
96 throw new HTTPProxyException(httpReponse.substring(13), errorCode);
|
|
97 }
|
|
98
|
307
|
99 while (reader.readLine() != null) {
|
273
|
100 // Read until empty line
|
|
101 }
|
|
102 }
|
|
103 }
|