Is there a way to upload a file to a FTP server when behind an HTTP proxy ?
It seems that uploading a file is not supported behind an HTTP Proxy using .Net Webclient
Hi I had the same issue - the resolution was to create the proxy object and derive the defaultcredentials - this should be fine provided your application is been run with a network account -
FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(uri));
System.Net.WebProxy proxy = System.Net.WebProxy.GetDefaultProxy();
proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
// set the ftpWebRequest proxy
reqFTP.Proxy = proxy;
This resolved the issue for me.
In active FTP mode, the server initiates a data connection to the client. If the client is behind an HTTP proxy, this obviously won't work. In passive FTP mode it is the client who initiates both the initial and the data connections. Since HTTP proxies can tunnel arbitrary outgoing TCP connections (using the CONNECT method), it should be possible to access an FTP server in passive mode via an HTTP proxy.
The FtpWebRequest
seems to support passive mode. However, I don't understand why file download and directory listings are supported, whereas file upload, which also uses the same data connection, is not.
Have you confirmed that FtpWebRequest
configured for passive mode does not work via an HTTP proxy through which directory listings/file download work just fine?
I'm not sure if all HTTP proxies work in the same way, but I managed to cheat ours by simply creating an HTTP request to access resource on URI ftp://user:pass@your.server.com/path.
Sadly, to create an instance of HttpWebRequest you should use WebRequest.Create. And if you do that you can't create an HTTP request for ftp:// schema.
So I used a bit of reflection to invoke a non-public constructor which does that:
var ctor = typeof(HttpWebRequest).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
null,
new Type[] { typeof(Uri), typeof(ServicePoint) },
null);
var req = (WebRequest)ctor.Invoke(new object[] { new Uri("ftp://user:pass@host/test.txt"), null });
req.Proxy = new WebProxy("myproxy", 8080);
req.Method = WebRequestMethods.Http.Put;
using (var inStream = req.GetRequestStream())
{
var buffer = Encoding.ASCII.GetBytes("test upload");
inStream.Write(buffer, 0, buffer.Length);
}
using (req.GetResponse())
{
}
You can also use other methods like "DELETE" for other tasks.
In my case, it worked like a charm.
Our Rebex FTP/SSL can use HTTP proxy. It's not free, though...
// initialize FTP client
Ftp client = new Ftp();
// setup proxy details
client.Proxy.ProxyType = FtpProxyType.HttpConnect;
client.Proxy.Host = proxyHostname;
client.Proxy.Port = proxyPort;
// add proxy username and password when needed
client.Proxy.UserName = proxyUsername;
client.Proxy.Password = proxyPassword;
// connect, login
client.Connect(hostname, port);
client.Login(username, password);
// do some work
// ...
// disconnect
client.Disconnect();
One solution is to try Mono's implementation of FtpWebRequest. I had a look at its source code and it appears it'll be easy to modify so that all connections (control and data) are tunneled via an HTTP proxy.
You establish a TCP connection to your HTTP proxy instead of the actual FTP server. Then you send CONNECT myserver:21 HTTP/1.0
followed by two CRLFs (CRLF = \r\n). If the proxy needs authentication, you need to use HTTP/1.1 and also send a proxy authentication header with the credentials. Then you need to read the first line of the response. If it starts with "HTTP/1.0 200
" or "HTTP/1.1 200
", then you (the rest of the code) can continue using the connection as though it's connected directly to the FTP server.
Id don't really see the connection between a http proxy and uploading to an ftp server. If you use the http proxy class thats for accessing http resources trough a http proxy. ftp is another protocol and the ftp proxies use a different protocol.