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