kerryjiang / WebSocket4Net

A popular .NET WebSocket Client
Apache License 2.0
771 stars 274 forks source link

Connection via proxy is not working #34

Open thomaslevesque opened 9 years ago

thomaslevesque commented 9 years ago

I'm trying to connect to websocket via a Squid proxy. I'm passing the IP address and port via the httpConnectProxy parameter of the WebSocket constructor.

If I try to connect to a ws:// URL, I get a 400 error from the proxy. With a wss:// URL, I get an SSL error ("The handshake failed due to an unexpected packet format").

The same scenarios (normal and secure connection) work fine with System.Net.WebSockets.ClientWebSocket. So I used Wireshark to compare the behavior of both implementation, and I realized that System.Net.WebSockets.ClientWebSocket is using HTTP CONNECT tunelling, whereas WebSocket4Net is sending the handshake request directly to the proxy. This behavior means that :

IMO WebSocket4Net should use HTTP CONNECT tunelling, it would work in much more situations.

Also, I see there's a Proxy property in addition to the httpConnectProxy parameter. What's the difference? What can I set the property to ? I don't see any implementation of IProxyConnector in the library.

RobertoSchneiders commented 9 years ago

Have you tried this @thomaslevesque?

thomaslevesque commented 9 years ago

@RobertoSchneiders commented on 22 sept. 2015 15:52 UTC+2:

Have you tried this @thomaslevesque?

No, I haven't. I'll give it a try. Thanks!

kerryjiang commented 9 years ago

@thomaslevesque there is assembly in SuperSocket.ClientEgnine called SuperSocket.ClientEngine.Proxy. All implementations of IProxyConnector locate in it.

thomaslevesque commented 9 years ago

@kerryjiang, where is that assembly? It doesn't seem to be in the NuGet package.

Anyway, I don't think I can use it directly, because of the way SuperSocket is ILMerged into WebSocket4Net. SuperSocket.ClientEngine.Proxy references the IProxyConnector from SuperSocket.ClientEngine, not the one from WebSocket4Net...

kerryjiang commented 9 years ago

Try download it from here: https://github.com/kerryjiang/WebSocket4Net/tree/master/Reference/SuperSocket.ClientEngine/Net40/Release

thomaslevesque commented 9 years ago

@kerryjiang , thanks, but it still has the assembly identity problem I mentioned... The only option seems to be to copy the HttpConnectProxy code into my project, as suggested in the StackOverflow answer linked by @RobertoSchneiders

Also, HttpConnectProxy doesn't seem to support proxy authentication (or am I missing something?)

RobertoSchneiders commented 9 years ago

I think it is possible to use proxy authentication adding the user and password in the url, something like this:

http://username:password@proxy_url:port

I'm not sure

thomaslevesque commented 9 years ago

@RobertoSchneiders, no, because you don't pass a URI, you pass a EndPoint (DnsEndPoint or IPEndPoint). I think I can pass the credentials in a Proxy-Authorization HTTP header, but right now I'm hitting other issues related to the buffer size...

kerryjiang commented 9 years ago

There is another parameter for http header items.

thomaslevesque commented 9 years ago

@kerryjiang commented on 22 sept. 2015 18:44 UTC+2:

There is another parameter for http header items.

Yes, I'm already using it ;)

thomaslevesque commented 9 years ago

OK, I eventually managed to connect, but I had to make several changes to HttpConnectProxy:

But it's still not robust enough; if the proxy returns any status other than 2xx, HttpConnectProxy just throws an error saying "the proxy server refused the connection", with no details at all. So I can't even detect if the credentials are incorrect...

RobertoSchneiders commented 9 years ago

@thomaslevesque Can you share your code? I'll suggest to you send a Pull Request with your work in progress.

It probably will make easier to understand the problems and help you. I don't know if I will be able to help, but I can try. I also need this proxy support.

thomaslevesque commented 9 years ago

@RobertoSchneiders, here are my changes: https://github.com/thomaslevesque/SuperSocket.ClientEngine/commit/18109a20bdbe9d83709e64b7b3c9e650e4af8a94

I don't want to send a pull request right now, because it's more a POC than anything else at this point. The value of the Proxy-Authorization header has to be provided manually, which isn't very convenient. Also, I'd like to add some specific handling for HTTP status 407 (Proxy authentication required), e.g. extract the authentication challenge from the Proxy-Authenticate header and include it in the exception.

thomaslevesque commented 9 years ago

@kerryjiang, it seems I'm unable to receive the response if it contains a body, I get the error "protocol error: more data has been received". It happens if the server returns HTTP status 407 for instance. Why does it matter if there is a body after the headers ? It should just be ignored... I think this test should be removed:

        if (e.Offset + e.BytesTransferred > responseLength + m_LineSeparator.Length)
        {
            OnException("protocol error: more data has been received");
            return;
        }

Do you see any reason to keep it?

osullivj commented 8 years ago

Thanks @thomaslevesque for the auth patch and @RobertoSchneiders for the proxy fix. I've applied both in my Excel addin - SSAddin - which @govert's ExcelDNA to push websocket sourced ticking data into Excel.

andrewooi99 commented 8 years ago

Followed this http://stackoverflow.com/questions/23024121/how-to-use-proxies-with-the-websocket4net-library and it hit exception that the remoteEndPoint is null in Connect method in SuperSocket.ClientEngine.Proxy.

gkalyanxo commented 8 years ago

@sohaimeng, I am facing the same issue. Were you able to figure out how to fix it? Thanks.

scolestock commented 8 years ago

I could certainly be wrong, but I believe that the changes introduced in this commit of SuperSocket.ClientEngine likely caused proxies to stop working correctly. They work for us back in the 0.14.1 version (c54a0cf). The refactoring in WebSocket.cs between these two versions to accommodate the change in AsyncTcpSession may have caused this to break.

kerryjiang commented 8 years ago

OK, I'll review the code.

I am really sorry about my late responses about the issues of my open source projects. I just moved to US a couple of months ago, so I am very busy on my work and my personal affairs.

andrewooi99 commented 7 years ago

The latest beta version 0.15.0-beta6 solved remoteEndPoint is null problem.

I wonder if "the proxy server refused the connection" & "proxy error ---> System.Exception: receive buffer size has been exceeded" had been solved.

I tested 3 approaches where the 1st works fine but others not working :

  1. Use fiddler as proxy (without proxy credential) and it works fine, able to see websocket stream in fiddler.
  2. Use fiddler as proxy (with proxy credential) and get "the proxy server refused the connection". I believe i used the websocket correctly by passing string proxyAuthInfo = String.Join(":", proxyUsername,proxyPassword); proxyAuthInfo = Convert.ToBase64String(Encoding.Default.GetBytes(proxyAuthInfo)); customHeaderList = new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("Authorization", "Basic " + proxyAuthInfo)};
  3. Use squid as proxy (with proxy credential) and get "proxy error ---> System.Exception: receive buffer size has been exceeded" had been solved".