FTP File Upload with HTTP Proxy

2019-01-13 21:14发布

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. (http://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest.proxy.aspx).

If there is no workaround ? If not, do you know a good and free FTP library I can use ?

Edit: Unfortunately, I don't have any FTP proxy to connect to.

标签: c# proxy ftp
13条回答
我只想做你的唯一
2楼-- · 2019-01-13 22:07

I've just had the same problem.

My primary goal was to upload a file to an ftp. And I didn't care if my traffic would go through proxy or not.

So I've just set FTPWebRequest.Proxy property to null right after FTPWebRequest.Create(uri).

And it worked. Yes, I know this solution is not the greatest one. And more of that, I don't get why did it work. But the goal is complete, anyway.

查看更多
看我几分像从前
3楼-- · 2019-01-13 22:09

As Alexander says, HTTP proxies can proxy arbitrary traffic. What you need is an FTP Client that has support for using a HTTP Proxy. Alexander is also correct that this would only work in passive mode.

My employer sells such an FTP client, but it is a enterprise level tool that only comes as part of a very large system.

I'm certain that there are others available that would better fit your needs.

查看更多
Lonely孤独者°
4楼-- · 2019-01-13 22:11

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.

查看更多
Luminary・发光体
5楼-- · 2019-01-13 22:12

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.

查看更多
做个烂人
6楼-- · 2019-01-13 22:16

Damn these unfree applications and components!!! Here is my open source C# code that can uploads file to FTP via HTTP proxy.

        public bool UploadFile(string localFilePath, string remoteDirectory)
    {
        var fileName = Path.GetFileName(localFilePath);
        string content;
        using (var reader = new StreamReader(localFilePath))
            content = reader.ReadToEnd();

        var proxyAuthB64Str = Convert.ToBase64String(Encoding.ASCII.GetBytes(_proxyUserName + ":" + _proxyPassword));
        var sendStr = "PUT ftp://" + _ftpLogin + ":" + _ftpPassword
            + "@" + _ftpHost + remoteDirectory + fileName + " HTTP/1.1\n"
            + "Host: " + _ftpHost + "\n"
            + "User-Agent: Mozilla/4.0 (compatible; Eradicator; dotNetClient)\n" + "Proxy-Authorization: Basic " + proxyAuthB64Str + "\n"
            + "Content-Type: application/octet-stream\n"
            + "Content-Length: " + content.Length + "\n"
            + "Connection: close\n\n" + content;

        var sendBytes = Encoding.ASCII.GetBytes(sendStr);

        using (var proxySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
        {
            proxySocket.Connect(_proxyHost, _proxyPort);
            if (!proxySocket.Connected)
                throw new SocketException();
            proxySocket.Send(sendBytes);

            const int recvSize = 65536;
            var recvBytes = new byte[recvSize];
            proxySocket.Receive(recvBytes, recvSize, SocketFlags.Partial);

            var responseFirstLine = new string(Encoding.ASCII.GetChars(recvBytes)).Split("\n".ToCharArray()).Take(1).ElementAt(0);
            var httpResponseCode = Regex.Replace(responseFirstLine, @"HTTP/1\.\d (\d+) (\w+)", "$1");
            var httpResponseDescription = Regex.Replace(responseFirstLine, @"HTTP/1\.\d (\d+) (\w+)", "$2");
            return httpResponseCode.StartsWith("2");
        }
        return false;
    }
查看更多
Evening l夕情丶
7楼-- · 2019-01-13 22:20

If there's a way for you to upload a file via FTP without C# then it should also be possible in C#. Does uploading via browser or an FTP client work?

The one FTP library I like the most is .NET FTP Client library.

查看更多
登录 后发表回答