001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.net.ftp; 019 020 import java.io.BufferedReader; 021 import java.io.IOException; 022 import java.io.InputStream; 023 import java.io.InputStreamReader; 024 import java.io.OutputStream; 025 import java.io.UnsupportedEncodingException; 026 import java.net.Socket; 027 import java.net.SocketException; 028 import java.util.ArrayList; 029 import java.util.List; 030 031 import org.apache.commons.net.util.Base64; 032 033 /** 034 * Experimental attempt at FTP client that tunnels over an HTTP proxy connection. 035 * 036 * @author rory 037 * @since 2.2 038 */ 039 public class FTPHTTPClient extends FTPClient { 040 private final String proxyHost; 041 private final int proxyPort; 042 private final String proxyUsername; 043 private final String proxyPassword; 044 private String host; 045 private int port; 046 047 private final byte[] CRLF; 048 private final Base64 base64 = new Base64(); 049 050 public FTPHTTPClient(String proxyHost, int proxyPort, String proxyUser, String proxyPass) { 051 this.proxyHost = proxyHost; 052 this.proxyPort = proxyPort; 053 this.proxyUsername = proxyUser; 054 this.proxyPassword = proxyPass; 055 056 try { 057 CRLF = "\r\n".getBytes(getControlEncoding()); 058 } catch (UnsupportedEncodingException e) { 059 throw new RuntimeException(e); 060 } 061 } 062 063 public FTPHTTPClient(String proxyHost, int proxyPort) { 064 this(proxyHost, proxyPort, null, null); 065 } 066 067 068 @Override 069 protected Socket _openDataConnection_(int command, String arg) 070 throws IOException { 071 Socket socket = new Socket(host, port); 072 InputStream is = socket.getInputStream(); 073 OutputStream os = socket.getOutputStream(); 074 075 tunnelHandshake(host, port, is, os); 076 077 return socket; 078 } 079 080 @Override 081 public void connect(String host, int port) throws SocketException, 082 IOException { 083 this.host = host; 084 this.port = port; 085 086 _socket_ = new Socket(proxyHost, proxyPort); 087 _input_ = _socket_.getInputStream(); 088 _output_ = _socket_.getOutputStream(); 089 try { 090 tunnelHandshake(host, port, _input_, _output_); 091 } 092 catch (Exception e) { 093 IOException ioe = new IOException("Could not connect to " + host); 094 ioe.initCause(e); 095 throw ioe; 096 } 097 } 098 099 private void tunnelHandshake(String host, int port, InputStream input, OutputStream output) throws IOException, 100 UnsupportedEncodingException { 101 final String connectString = "CONNECT " + host + ":" + port + " HTTP/1.1"; 102 103 _output_.write(connectString.getBytes(getControlEncoding())); 104 _output_.write(CRLF); 105 106 if (proxyUsername != null && proxyPassword != null) { 107 final String header = "Proxy-Authorization: Basic " 108 + base64.encode(proxyUsername + ":" + proxyPassword) + "\r\n"; 109 _output_.write(header.getBytes("UTF-8")); 110 _output_.write(CRLF); 111 112 List<String> response = new ArrayList<String>(); 113 BufferedReader reader = new BufferedReader( 114 new InputStreamReader(_input_)); 115 116 for (String line = reader.readLine(); line != null 117 && line.length() > 0; line = reader.readLine()) { 118 response.add(line); 119 } 120 121 int size = response.size(); 122 if (size == 0) { 123 throw new IOException("No response from proxy"); 124 } 125 126 String code = null; 127 String resp = response.get(0); 128 if (resp.startsWith("HTTP/") && resp.length() >= 12) { 129 code = resp.substring(9, 12); 130 } else { 131 throw new IOException("Invalid response from proxy: " + resp); 132 } 133 134 if (!"200".equals(code)) { 135 StringBuilder msg = new StringBuilder(); 136 msg.append("HTTPTunnelConnector: connection failed\r\n"); 137 msg.append("Response received from the proxy:\r\n"); 138 for (String line : response) { 139 msg.append(line); 140 msg.append("\r\n"); 141 } 142 throw new IOException(msg.toString()); 143 } 144 } 145 } 146 } 147 148