Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Proxy support #395

Merged
merged 4 commits into from Jun 5, 2016
Merged

Conversation

oldshuren
Copy link
Contributor

This pull request added support to use SocketRocket behind http proxy.

The proxy setting is read from the system configuration. PAC is also supported.

If there is proxy in the system configuration. Instead open network stream to the web socket server, the network stream to the proxy server is opened. Then we send HTTP CONNECT with the web socket server address to the proxy server. After receiving 200 OK status, it operates like normal network stream.

@ghost
Copy link

ghost commented May 30, 2016

Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. In order for us to review and merge your code, please sign up at https://code.facebook.com/cla - and if you have received this in error or have any questions, please drop us a line at cla@fb.com. Thanks!

@oldshuren
Copy link
Contributor Author

Signed GLA

@ghost
Copy link

ghost commented May 31, 2016

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks!

@ghost ghost added the CLA Signed label May 31, 2016
}

// get proxy setting from device setting
-(void) configureProxy
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Please match the overall style - aka - (void)_configureProxy

@nlutsenko
Copy link
Contributor

@oldshuren, than you so much for figuring out the CFNetwork approach to auto-proxy configuration.
The PR looks like a really great start. I put some nitpicky notes on it, please note that all of these are applicable to the entire code change.

Also, if we could make the proxy configuration a self contained set of functions, or even a self contained class - that would be much better for code maintainability and reuse.

@madlymad
Copy link

madlymad commented Jun 1, 2016

I can verify that the patch works for the HTTPS connection through proxy that is set with the pac file URL in the device's WiFi settings. The corporate proxy does not support socks connections.

Tested on iPhone 4S (iOS 9.3.1 build 13E283).

@oldshuren
Copy link
Contributor Author

I think we can make a class to handle the proxy configuration and
connecting to the http server. The completion block will be invoke with
either two input/output stream for success, or NSError for error.

BTW, if I make the change, do I need to submit a new pull request?

Thanks,

Dong

On 5/31/16 2:31 PM, Nikita Lutsenko wrote:

@oldshuren https://github.com/oldshuren, than you so much for
figuring out the CFNetwork approach to auto-proxy configuration.
The PR looks like a really great start. I put some nitpicky notes on
it, please note that all of these are applicable to the entire code
change.

Also, if we could make the proxy configuration a self contained set of
functions, or even a self contained class - that would be much better
for code maintainability and reuse.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#395 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AHRzfHpapIOusIjjdNEe1CiDE8y1_yMeks5qHH6VgaJpZM4Ip_XE.

@nlutsenko
Copy link
Contributor

I think we can make a class to handle the proxy configuration and
connecting to the http server. The completion block will be invoke with
either two input/output stream for success, or NSError for error.

Sounds great. Looking forward to this!

BTW, if I make the change, do I need to submit a new pull request?

You can just force push the existing remote branch with git push -f which will update the pull request here automatically.

@oldshuren
Copy link
Contributor Author

Or create a class called NetSocket, which will handle proxy, open
network connection, send and receiving raw data?

Dong

On 5/31/16 2:31 PM, Nikita Lutsenko wrote:

@oldshuren https://github.com/oldshuren, than you so much for
figuring out the CFNetwork approach to auto-proxy configuration.
The PR looks like a really great start. I put some nitpicky notes on
it, please note that all of these are applicable to the entire code
change.

Also, if we could make the proxy configuration a self contained set of
functions, or even a self contained class - that would be much better
for code maintainability and reuse.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#395 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AHRzfHpapIOusIjjdNEe1CiDE8y1_yMeks5qHH6VgaJpZM4Ip_XE.

@nlutsenko
Copy link
Contributor

I would say - we are good just by using a single class for proxy setup here, I wouldn't advise a big change, like NetSocket implementation just yet, since it's slightly out of scope of the intention here (http proxy handling).

@gaborvass
Copy link

Hi,

Would be possible to add SOCKS proxy support as well?

Thanks,
Gabor

@oldshuren
Copy link
Contributor Author

I guess it is possible, but you have to use PAC, because you can not
input SOCK directly in iOS.

I'll take a look after I finish the HTTP proxy.

Cheers,

Dong

On 6/2/16 3:52 PM, Gabor Vass wrote:

Hi,

Would be possible to add SOCKS proxy support as well?

Thanks,
Gabor


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#395 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AHRzfLrwdIplbXjgSfWxR2R2nY5OV9mXks5qHzR3gaJpZM4Ip_XE.

@gaborvass
Copy link

you can add it on ios like this:

CFMutableDictionaryRef socksConfig = CFDictionaryCreateMutableCopy(NULL, 0, proxyDict);
CFStringRef socksProxyHost = CFDictionaryGetValue(proxyDict, @"SOCKSProxy");
CFNumberRef socksProxyPort = CFDictionaryGetValue(proxyDict, @"SOCKSPort");
if (socksProxyHost != NULL && socksProxyPort != NULL)
{
CFDictionarySetValue(socksConfig, kCFStreamPropertySOCKSProxyHost, socksProxyHost);
CFDictionarySetValue(socksConfig, kCFStreamPropertySOCKSProxyPort, socksProxyPort);
CFDictionarySetValue(socksConfig, kCFStreamPropertySOCKSVersion, kCFStreamSocketSOCKSVersion4);
CFReadStreamSetProperty(readStream, kCFStreamPropertySOCKSProxy, proxyDict);
CFWriteStreamSetProperty(writeStream, kCFStreamPropertySOCKSProxy, proxyDict);
CFRelease(socksProxyHost);
CFRelease(socksProxyPort);
}
CFRelease(socksConfig);

cheers,
Gabor

@oldshuren
Copy link
Contributor Author

I pushed new update. Proxy handling was moved to ProxyConnect.{h|m}

Socks support is added. It turns out Socks support is easier that HTTP, Apple's CFNetwork already have Socks support, you just need to configuration from system settings.

@oldshuren
Copy link
Contributor Author

@gaborvass I did it just like your suggestion, but on the NSStream. And the system configure only provide host, port, username and password. So I just ignore the version attribute.

I tested it with the ssh Socks tunnel, it works perfectly.

@gaborvass
Copy link

@oldshuren thanks a lot!

@@ -0,0 +1,6 @@
#import <Foundation/Foundation.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is missing the copyright declaration, which is required for all our source files.
Please copy it from SRError.h

@nlutsenko
Copy link
Contributor

nlutsenko commented Jun 3, 2016

@oldshuren, this looks good overall, few nits here and there (there is more but I skipped them for now).

Overall notes:

  • Runloop schedule/unschedule is hacky, but will work just as fine.
  • Love the fact that we decoupled this code from the SRWebSocket itself, it's way more manageable this way!
  • We have a thread safety problem here, because the completion block is not guaranteed to be called on the same thread as it was scheduled, you might want to wrap the completion either in the work queue scheduling or maybe add a locking around it (the latter is outside of the scope of the current change)
  • Since the root folder of SocketRocket is intended for public classes only - merging this right now will make it public, which is something we would want to avoid. Can you please move the ProxyConnect into SocketRocket/Internal?

As per more nits, styling, structuring:
Would you want to go through few iterations before I merge this? Or would it be more helpful if we merge this after fixing few things and I'll take a pass on structuring/linting/adding thread safety and unifying the style here?

The minimum required changes to merge regardless of the path we take:

  • Adding copyrights
  • Renaming ProxyConnect to SRProxyConnect
  • Moving SRProxyConnect into SocketRocket/Internal

Let me know how I can support you here.

@oldshuren
Copy link
Contributor Author

Initially I had the stream running in the default Runloop, the normal
connection worked fine, but the connection to the proxy server didn't
work. So I'm just using SRWebSocket own Runloop.

You don't need to unschedule in the proxy handling code, but it requires
more change in the main SRWebSocket.m :(

I think I'll do the minimum necessary changes and let you change the
other part. It is much easier this way.

Thanks,

Dong

On 6/3/16 2:35 PM, Nikita Lutsenko wrote:

@oldshuren https://github.com/oldshuren, this looks good overall,
few nits here and there (there is more but I skipped them for now).

Overall notes:

  • Runloop schedule/unschedule is hacky, but will work just as fine.
  • Love the fact that we decoupled this code from the |SRWebSocket|
    itself, it's way more manageable this way!
  • We have a thread safety problem here, because the completion block
    is not guaranteed to be called on the same thread as it was
    scheduled, you might want to wrap the completion either in the
    work queue scheduling.
  • Since the root folder of |SocketRocket| is intended for public
    classes only - merging this right now will make it public, which
    is something we would want to avoid. Can you please move the
    |ProxyConnect| into |SocketRocket/Internal|?

As per more nits, styling, structuring:
Would you want to go through few iterations before I merge this? Or
would it be more helpful if we merge this after fixing few things and
I'll take a pass on structuring/linting/adding thread safety and
unifying the style here?

The minimum required changes to merge this:

  • Adding copyrights
  • Renaming |ProxyConnect| to |SRProxyConnect|
  • Moving |SRProxyConnect| into |SocketRocket/Internal|

Let me know how I can support you here.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#395 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AHRzfJxbllxStzhJwJcw8Ls2lT3Id4Oxks5qIHP_gaJpZM4Ip_XE.

@oldshuren
Copy link
Contributor Author

On 6/3/16 2:35 PM, Nikita Lutsenko wrote:

  • We have a thread safety problem here, because the completion block
    is not guaranteed to be called on the same thread as it was
    scheduled, you might want to wrap the completion either in the
    work queue scheduling.

I tried to call the completion handler in the invoking thread, that is
main thread. There seems some race conditions around, it sometimes
worked, sometime didn't.

The proxy code doesn't have access to the SRWebSocket's worker queue. So
I cannot wrap it in proxy code. But in the main SRWebSocket, didConnect
is wrapped in the work queue, as

             dispatch_async(_workQueue, ^{
                     [weakSelf didConnect];
                 });

So I think it should be fine.

Dong

@oldshuren
Copy link
Contributor Author

One question, does the copyrights have to say Facebook?

Thanks,

Dong

On 6/3/16 2:35 PM, Nikita Lutsenko wrote:

@oldshuren https://github.com/oldshuren, this looks good overall,
few nits here and there (there is more but I skipped them for now).

Overall notes:

  • Runloop schedule/unschedule is hacky, but will work just as fine.
  • Love the fact that we decoupled this code from the |SRWebSocket|
    itself, it's way more manageable this way!
  • We have a thread safety problem here, because the completion block
    is not guaranteed to be called on the same thread as it was
    scheduled, you might want to wrap the completion either in the
    work queue scheduling.
  • Since the root folder of |SocketRocket| is intended for public
    classes only - merging this right now will make it public, which
    is something we would want to avoid. Can you please move the
    |ProxyConnect| into |SocketRocket/Internal|?

As per more nits, styling, structuring:
Would you want to go through few iterations before I merge this? Or
would it be more helpful if we merge this after fixing few things and
I'll take a pass on structuring/linting/adding thread safety and
unifying the style here?

The minimum required changes to merge this:

  • Adding copyrights
  • Renaming |ProxyConnect| to |SRProxyConnect|
  • Moving |SRProxyConnect| into |SocketRocket/Internal|

Let me know how I can support you here.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#395 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AHRzfJxbllxStzhJwJcw8Ls2lT3Id4Oxks5qIHP_gaJpZM4Ip_XE.

@nlutsenko
Copy link
Contributor

@oldshuren, yes, that's an explicit requirement.

@oldshuren
Copy link
Contributor Author

Ok

Dong

On 6/3/16 5:07 PM, Nikita Lutsenko wrote:

@oldshuren https://github.com/oldshuren, yes, that's an explicit
requirement.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#395 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AHRzfBl0b_riLVn2swFaTNriq273IJE-ks5qIJd5gaJpZM4Ip_XE.

@nlutsenko
Copy link
Contributor

Perfect, than you for implementing this.
Merging now, and am going to send another pull request that lints the change as well as cleans up some leftovers.

@@ -1570,7 +1567,7 @@ - (NSOperationQueue *_Nullable)delegateOperationQueue

@end

//#define SR_ENABLE_LOG
#define SR_ENABLE_LOG
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi guys. Great work and apologies in advance for coming late to the party.

Did you mean to enable logging by default here for all builds?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be disabled on the current master branch.
Let me know if it's not. Shouldn't be enabled by default.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

master branch is ok

(should have checked there first - sorry for the wasted time)

@nlutsenko nlutsenko added this to the 0.6.0 milestone Oct 31, 2016
@happy-tanuki
Copy link

happy-tanuki commented Feb 9, 2017

This is great job!
Why not the tickets #114 and #346 is closed?

madlymad pushed a commit to madlymad/SocketRocket that referenced this pull request Jul 6, 2017
* Add Proxy support

* move proxy to a class, add socks support

* should use weakSelf

* Move ProxyConnect to Internal/Proxy/SRProxyConnect
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants