using System; using System.IO; using System.Text.RegularExpressions; namespace FluentFTP.Proxy { /// A FTP client with a HTTP 1.1 proxy implementation. public class FtpClientHttp11Proxy : FtpClientProxy { /// A FTP client with a HTTP 1.1 proxy implementation /// Proxy information public FtpClientHttp11Proxy(ProxyInfo proxy) : base(proxy) { ConnectionType = "HTTP 1.1 Proxy"; } /// Redefine the first dialog: HTTP Frame for the HTTP 1.1 Proxy protected override void Handshake() { var proxyConnectionReply = GetReply(); if (!proxyConnectionReply.Success) throw new FtpException("Can't connect " + Host + " via proxy " + Proxy.Host + ".\nMessage : " + proxyConnectionReply.ErrorMessage); } /// /// Creates a new instance of this class. Useful in FTP proxy classes. /// protected override FtpClient Create() { return new FtpClientHttp11Proxy(Proxy); } /// /// Connects to the server using an existing /// /// The existing socket stream protected override void Connect(FtpSocketStream stream) { Connect(stream, Host, Port, FtpIpVersion.ANY); } /// /// Connects to the server using an existing /// /// The existing socket stream /// Host name /// Port number /// IP version to use protected override void Connect(FtpSocketStream stream, string host, int port, FtpIpVersion ipVersions) { base.Connect(stream); var writer = new StreamWriter(stream); writer.WriteLine("CONNECT {0}:{1} HTTP/1.1", host, port); writer.WriteLine("Host: {0}:{1}", host, port); if (Proxy.Credentials != null) { var credentialsHash = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(Proxy.Credentials.UserName + ":"+ Proxy.Credentials.Password)); writer.WriteLine("Proxy-Authorization: Basic "+ credentialsHash); } writer.WriteLine("User-Agent: custom-ftp-client"); writer.WriteLine(); writer.Flush(); ProxyHandshake(stream); } private void ProxyHandshake(FtpSocketStream stream) { var proxyConnectionReply = GetProxyReply(stream); if (!proxyConnectionReply.Success) throw new FtpException("Can't connect " + Host + " via proxy " + Proxy.Host + ".\nMessage : " + proxyConnectionReply.ErrorMessage); } private FtpReply GetProxyReply( FtpSocketStream stream ) { FtpReply reply = new FtpReply(); string buf; #if !CORE14 lock ( Lock ) { #endif if( !IsConnected ) throw new InvalidOperationException( "No connection to the server has been established." ); stream.ReadTimeout = ReadTimeout; while( ( buf = stream.ReadLine( Encoding ) ) != null ) { Match m; FtpTrace.WriteLine(FtpTraceLevel.Info, buf); if( ( m = Regex.Match( buf, @"^HTTP/.*\s(?[0-9]{3}) (?.*)$" ) ).Success ) { reply.Code = m.Groups[ "code" ].Value; reply.Message = m.Groups[ "message" ].Value; break; } reply.InfoMessages += ( buf+"\n" ); } // fixes #84 (missing bytes when downloading/uploading files through proxy) while( ( buf = stream.ReadLine( Encoding ) ) != null ) { FtpTrace.WriteLine(FtpTraceLevel.Info, buf); if (FtpExtensions.IsNullOrWhiteSpace(buf)) { break; } reply.InfoMessages += ( buf+"\n" ); } #if !CORE14 } #endif return reply; } } }