001 /* 002 * ftp4j - A pure Java FTP client library 003 * 004 * Copyright (C) 2008 Carlo Pelliccia (www.sauronsoftware.it) 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 018 */ 019 package it.sauronsoftware.ftp4j.connectors; 020 021 import it.sauronsoftware.ftp4j.FTPConnection; 022 import it.sauronsoftware.ftp4j.FTPConnector; 023 import it.sauronsoftware.ftp4j.base64.Base64; 024 025 import java.io.BufferedReader; 026 import java.io.IOException; 027 import java.io.InputStream; 028 import java.io.InputStreamReader; 029 import java.io.OutputStream; 030 import java.net.Socket; 031 import java.util.ArrayList; 032 033 /** 034 * This one connects a remote ftp host via a HTTP 1.1 proxy which allows 035 * tunneling through the HTTP CONNECT method. 036 * 037 * @author Carlo Pelliccia 038 */ 039 public class HTTPTunnelConnector implements FTPConnector { 040 041 /** 042 * The proxy host name. 043 */ 044 private String proxyHost; 045 046 /** 047 * The proxy port. 048 */ 049 private int proxyPort; 050 051 /** 052 * The proxyUser for proxy authentication. 053 */ 054 private String proxyUser; 055 056 /** 057 * The proxyPass for proxy authentication. 058 */ 059 private String proxyPass; 060 061 /** 062 * Builds the connector. 063 * 064 * @param proxyHost 065 * The proxy host name. 066 * @param proxyPort 067 * The proxy port. 068 * @param proxyUser 069 * The username for proxy authentication. 070 * @param proxyPass 071 * The password for proxy authentication. 072 */ 073 public HTTPTunnelConnector(String proxyHost, int proxyPort, 074 String proxyUser, String proxyPass) { 075 this.proxyHost = proxyHost; 076 this.proxyPort = proxyPort; 077 this.proxyUser = proxyUser; 078 this.proxyPass = proxyPass; 079 } 080 081 /** 082 * Builds the connector. 083 * 084 * @param proxyHost 085 * The proxy host name. 086 * @param proxyPort 087 * The proxy port. 088 */ 089 public HTTPTunnelConnector(String proxyHost, int proxyPort) { 090 this(proxyHost, proxyPort, null, null); 091 } 092 093 private FTPConnection connect(String host, int port) throws IOException { 094 // The CRLF sequence. 095 byte[] CRLF = "\r\n".getBytes("UTF-8"); 096 // The connect command line. 097 String connect = "CONNECT " + host + ":" + port + " HTTP/1.1"; 098 // A connection status flag. 099 boolean connected = false; 100 // The socket for the connection with the proxy. 101 Socket socket = null; 102 InputStream in = null; 103 OutputStream out = null; 104 // FTPConnection routine. 105 try { 106 socket = new Socket(proxyHost, proxyPort); 107 in = socket.getInputStream(); 108 out = socket.getOutputStream(); 109 // Send the CONNECT request. 110 out.write(connect.getBytes("UTF-8")); 111 out.write(CRLF); 112 // Auth headers 113 if (proxyUser != null && proxyPass != null) { 114 String header = "Proxy-Authorization: Basic " 115 + Base64.encode(proxyUser + ":" + proxyPass) + "\r\n"; 116 out.write(header.getBytes("UTF-8")); 117 } 118 out.write(CRLF); 119 // Get the proxy response. 120 ArrayList responseLines = new ArrayList(); 121 BufferedReader reader = new BufferedReader( 122 new InputStreamReader(in)); 123 for (String line = reader.readLine(); line != null 124 && line.length() > 0; line = reader.readLine()) { 125 responseLines.add(line); 126 } 127 // Parse the response. 128 int size = responseLines.size(); 129 if (size < 1) { 130 throw new IOException( 131 "HTTPTunnelConnector: invalid proxy response"); 132 } 133 String code = null; 134 String response = (String) responseLines.get(0); 135 if (response.startsWith("HTTP/") && response.length() >= 12) { 136 code = response.substring(9, 12); 137 } else { 138 throw new IOException( 139 "HTTPTunnelConnector: invalid proxy response"); 140 } 141 if (!"200".equals(code)) { 142 StringBuffer msg = new StringBuffer(); 143 msg.append("HTTPTunnelConnector: connection failed\r\n"); 144 msg.append("Response received from the proxy:\r\n"); 145 for (int i = 0; i < size; i++) { 146 String line = (String) responseLines.get(i); 147 msg.append(line); 148 msg.append("\r\n"); 149 } 150 throw new IOException(msg.toString()); 151 } 152 connected = true; 153 } catch (IOException e) { 154 throw e; 155 } finally { 156 if (!connected) { 157 if (out != null) { 158 try { 159 out.close(); 160 } catch (Throwable t) { 161 ; 162 } 163 } 164 if (in != null) { 165 try { 166 in.close(); 167 } catch (Throwable t) { 168 ; 169 } 170 } 171 if (socket != null) { 172 try { 173 socket.close(); 174 } catch (Throwable t) { 175 ; 176 } 177 } 178 } 179 } 180 return new SocketConnection(socket, in, out); 181 } 182 183 public FTPConnection connectForCommunicationChannel(String host, int port) 184 throws IOException { 185 return connect(host, port); 186 } 187 188 public FTPConnection connectForDataTransferChannel(String host, int port) 189 throws IOException { 190 return connect(host, port); 191 } 192 193 }