|
@@ -10,64 +10,74 @@
|
|
#import "SRProxyConnect.h"
|
|
#import "SRProxyConnect.h"
|
|
#import "SRError.h"
|
|
#import "SRError.h"
|
|
#import "NSRunLoop+SRWebSocket.h"
|
|
#import "NSRunLoop+SRWebSocket.h"
|
|
|
|
+#import "SRURLUtilities.h"
|
|
|
|
|
|
static inline void SRProxyFastLog(NSString *format, ...);
|
|
static inline void SRProxyFastLog(NSString *format, ...);
|
|
|
|
|
|
-typedef void (^SRProxyConnectionCompletion)(NSError *error, NSInputStream *readStream, NSOutputStream *writeStream);
|
|
|
|
-
|
|
|
|
@interface SRProxyConnect() <NSStreamDelegate>
|
|
@interface SRProxyConnect() <NSStreamDelegate>
|
|
|
|
|
|
@property (nonatomic, strong) NSURL *url;
|
|
@property (nonatomic, strong) NSURL *url;
|
|
-@property (nonatomic, strong) NSInputStream * inputStream;
|
|
|
|
-@property (nonatomic, strong) NSOutputStream * outputStream;
|
|
|
|
|
|
+@property (nonatomic, strong) NSInputStream *inputStream;
|
|
|
|
+@property (nonatomic, strong) NSOutputStream *outputStream;
|
|
|
|
|
|
@end
|
|
@end
|
|
|
|
|
|
-@implementation SRProxyConnect {
|
|
|
|
-
|
|
|
|
- SRProxyConnectionCompletion _connectDoneHandler;
|
|
|
|
-
|
|
|
|
|
|
+@implementation SRProxyConnect
|
|
|
|
+{
|
|
|
|
+ SRProxyConnectCompletion _completion;
|
|
|
|
+
|
|
NSString *_httpProxyHost;
|
|
NSString *_httpProxyHost;
|
|
uint32_t _httpProxyPort;
|
|
uint32_t _httpProxyPort;
|
|
-
|
|
|
|
|
|
+
|
|
CFHTTPMessageRef _receivedHTTPHeaders;
|
|
CFHTTPMessageRef _receivedHTTPHeaders;
|
|
|
|
|
|
NSString *_socksProxyHost;
|
|
NSString *_socksProxyHost;
|
|
uint32_t _socksProxyPort;
|
|
uint32_t _socksProxyPort;
|
|
NSString *_socksProxyUsername;
|
|
NSString *_socksProxyUsername;
|
|
NSString *_socksProxyPassword;
|
|
NSString *_socksProxyPassword;
|
|
-
|
|
|
|
- BOOL _secure;
|
|
|
|
|
|
+
|
|
|
|
+ BOOL _connectionRequiresSSL;
|
|
|
|
|
|
NSMutableArray<NSData *> *_inputQueue;
|
|
NSMutableArray<NSData *> *_inputQueue;
|
|
NSOperationQueue * _writeQueue;
|
|
NSOperationQueue * _writeQueue;
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+///--------------------------------------
|
|
|
|
+#pragma mark - Init
|
|
|
|
+///--------------------------------------
|
|
|
|
+
|
|
-(instancetype)initWithURL:(NSURL *)url
|
|
-(instancetype)initWithURL:(NSURL *)url
|
|
{
|
|
{
|
|
self = [super init];
|
|
self = [super init];
|
|
if (!self) return self;
|
|
if (!self) return self;
|
|
-
|
|
|
|
|
|
+
|
|
_url = url;
|
|
_url = url;
|
|
_connectionRequiresSSL = SRURLRequiresSSL(url);
|
|
_connectionRequiresSSL = SRURLRequiresSSL(url);
|
|
-
|
|
|
|
|
|
+
|
|
_writeQueue = [[NSOperationQueue alloc] init];
|
|
_writeQueue = [[NSOperationQueue alloc] init];
|
|
_inputQueue = [NSMutableArray arrayWithCapacity:2];
|
|
_inputQueue = [NSMutableArray arrayWithCapacity:2];
|
|
|
|
|
|
return self;
|
|
return self;
|
|
}
|
|
}
|
|
|
|
|
|
--(void) openNetworkStreamWithCompletion:(void (^)(NSError *error, NSInputStream *readStream, NSOutputStream *writeStream ))completion
|
|
|
|
|
|
+///--------------------------------------
|
|
|
|
+#pragma mark - Open
|
|
|
|
+///--------------------------------------
|
|
|
|
+
|
|
|
|
+- (void)openNetworkStreamWithCompletion:(SRProxyConnectCompletion)completion
|
|
{
|
|
{
|
|
- _connectDoneHandler = completion;
|
|
|
|
|
|
+ _completion = completion;
|
|
[self _configureProxy];
|
|
[self _configureProxy];
|
|
}
|
|
}
|
|
|
|
|
|
--(void) _didConnect
|
|
|
|
|
|
+///--------------------------------------
|
|
|
|
+#pragma mark - Flow
|
|
|
|
+///--------------------------------------
|
|
|
|
+
|
|
|
|
+- (void)_didConnect
|
|
{
|
|
{
|
|
SRProxyFastLog(@"_didConnect, return streams");
|
|
SRProxyFastLog(@"_didConnect, return streams");
|
|
- if (_secure) {
|
|
|
|
|
|
+ if (_connectionRequiresSSL) {
|
|
if (_httpProxyHost) {
|
|
if (_httpProxyHost) {
|
|
// Must set the real peer name before turning on SSL
|
|
// Must set the real peer name before turning on SSL
|
|
SRProxyFastLog(@"proxy set peer name to real host %@", self.url.host);
|
|
SRProxyFastLog(@"proxy set peer name to real host %@", self.url.host);
|
|
@@ -78,24 +88,27 @@ typedef void (^SRProxyConnectionCompletion)(NSError *error, NSInputStream *readS
|
|
CFRelease(_receivedHTTPHeaders);
|
|
CFRelease(_receivedHTTPHeaders);
|
|
_receivedHTTPHeaders = NULL;
|
|
_receivedHTTPHeaders = NULL;
|
|
}
|
|
}
|
|
|
|
+
|
|
NSInputStream *inputStream = self.inputStream;
|
|
NSInputStream *inputStream = self.inputStream;
|
|
NSOutputStream *outputStream = self.outputStream;
|
|
NSOutputStream *outputStream = self.outputStream;
|
|
|
|
+
|
|
self.inputStream = nil;
|
|
self.inputStream = nil;
|
|
self.outputStream = nil;
|
|
self.outputStream = nil;
|
|
- [inputStream removeFromRunLoop:[NSRunLoop SR_networkRunLoop]
|
|
|
|
- forMode:NSDefaultRunLoopMode];
|
|
|
|
|
|
+
|
|
|
|
+ [inputStream removeFromRunLoop:[NSRunLoop SR_networkRunLoop] forMode:NSDefaultRunLoopMode];
|
|
inputStream.delegate = nil;
|
|
inputStream.delegate = nil;
|
|
outputStream.delegate = nil;
|
|
outputStream.delegate = nil;
|
|
- _connectDoneHandler(nil, inputStream, outputStream);
|
|
|
|
|
|
+
|
|
|
|
+ _completion(nil, inputStream, outputStream);
|
|
}
|
|
}
|
|
|
|
|
|
--(void) _failWithError:(NSError *)error
|
|
|
|
|
|
+- (void)_failWithError:(NSError *)error
|
|
{
|
|
{
|
|
SRProxyFastLog(@"_failWithError, return error");
|
|
SRProxyFastLog(@"_failWithError, return error");
|
|
if (!error) {
|
|
if (!error) {
|
|
error = SRHTTPErrorWithCodeDescription(500, 2132,@"Proxy Error");
|
|
error = SRHTTPErrorWithCodeDescription(500, 2132,@"Proxy Error");
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
if (_receivedHTTPHeaders) {
|
|
if (_receivedHTTPHeaders) {
|
|
CFRelease(_receivedHTTPHeaders);
|
|
CFRelease(_receivedHTTPHeaders);
|
|
_receivedHTTPHeaders = NULL;
|
|
_receivedHTTPHeaders = NULL;
|
|
@@ -106,21 +119,23 @@ typedef void (^SRProxyConnectionCompletion)(NSError *error, NSInputStream *readS
|
|
[self.outputStream close];
|
|
[self.outputStream close];
|
|
self.inputStream = nil;
|
|
self.inputStream = nil;
|
|
self.outputStream = nil;
|
|
self.outputStream = nil;
|
|
- _connectDoneHandler(error, nil, nil);
|
|
|
|
|
|
+ _completion(error, nil, nil);
|
|
}
|
|
}
|
|
|
|
|
|
// get proxy setting from device setting
|
|
// get proxy setting from device setting
|
|
--(void) _configureProxy
|
|
|
|
|
|
+- (void)_configureProxy
|
|
{
|
|
{
|
|
SRProxyFastLog(@"configureProxy");
|
|
SRProxyFastLog(@"configureProxy");
|
|
NSDictionary *proxySettings = CFBridgingRelease(CFNetworkCopySystemProxySettings());
|
|
NSDictionary *proxySettings = CFBridgingRelease(CFNetworkCopySystemProxySettings());
|
|
|
|
+
|
|
// CFNetworkCopyProxiesForURL doesn't understand ws:// or wss://
|
|
// CFNetworkCopyProxiesForURL doesn't understand ws:// or wss://
|
|
NSURL *httpURL;
|
|
NSURL *httpURL;
|
|
- if (_secure)
|
|
|
|
|
|
+ if (_connectionRequiresSSL) {
|
|
httpURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@", _url.host]];
|
|
httpURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@", _url.host]];
|
|
- else
|
|
|
|
|
|
+ } else {
|
|
httpURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@", _url.host]];
|
|
httpURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@", _url.host]];
|
|
-
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
NSArray *proxies = CFBridgingRelease(CFNetworkCopyProxiesForURL((__bridge CFURLRef)httpURL, (__bridge CFDictionaryRef)proxySettings));
|
|
NSArray *proxies = CFBridgingRelease(CFNetworkCopyProxiesForURL((__bridge CFURLRef)httpURL, (__bridge CFDictionaryRef)proxySettings));
|
|
if (proxies.count == 0) {
|
|
if (proxies.count == 0) {
|
|
SRProxyFastLog(@"configureProxy no proxies");
|
|
SRProxyFastLog(@"configureProxy no proxies");
|
|
@@ -136,8 +151,8 @@ typedef void (^SRProxyConnectionCompletion)(NSError *error, NSInputStream *readS
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- if ([proxyType isEqualToString:(NSString *)kCFProxyTypeAutoConfigurationJavaScript]) {
|
|
|
|
- NSString *script = settings[(NSString *)kCFProxyAutoConfigurationJavaScriptKey];
|
|
|
|
|
|
+ if ([proxyType isEqualToString:(__bridge NSString *)kCFProxyTypeAutoConfigurationJavaScript]) {
|
|
|
|
+ NSString *script = settings[(__bridge NSString *)kCFProxyAutoConfigurationJavaScriptKey];
|
|
if (script) {
|
|
if (script) {
|
|
[self _runPACScript:script];
|
|
[self _runPACScript:script];
|
|
return;
|
|
return;
|
|
@@ -148,9 +163,10 @@ typedef void (^SRProxyConnectionCompletion)(NSError *error, NSInputStream *readS
|
|
[self _openConnection];
|
|
[self _openConnection];
|
|
}
|
|
}
|
|
|
|
|
|
-- (void) _readProxySettingWithType:(NSString *)proxyType settings:(NSDictionary *)settings
|
|
|
|
|
|
+- (void)_readProxySettingWithType:(NSString *)proxyType settings:(NSDictionary *)settings
|
|
{
|
|
{
|
|
- if ([proxyType isEqualToString:(NSString *)kCFProxyTypeHTTP] || [proxyType isEqualToString:(NSString *)kCFProxyTypeHTTPS]) {
|
|
|
|
|
|
+ if ([proxyType isEqualToString:(NSString *)kCFProxyTypeHTTP] ||
|
|
|
|
+ [proxyType isEqualToString:(NSString *)kCFProxyTypeHTTPS]) {
|
|
_httpProxyHost = settings[(NSString *)kCFProxyHostNameKey];
|
|
_httpProxyHost = settings[(NSString *)kCFProxyHostNameKey];
|
|
NSNumber *portValue = settings[(NSString *)kCFProxyPortNumberKey];
|
|
NSNumber *portValue = settings[(NSString *)kCFProxyPortNumberKey];
|
|
if (portValue)
|
|
if (portValue)
|
|
@@ -176,21 +192,21 @@ typedef void (^SRProxyConnectionCompletion)(NSError *error, NSInputStream *readS
|
|
- (void)_fetchPAC:(NSURL *)PACurl
|
|
- (void)_fetchPAC:(NSURL *)PACurl
|
|
{
|
|
{
|
|
SRProxyFastLog(@"SRWebSocket fetchPAC:%@", PACurl);
|
|
SRProxyFastLog(@"SRWebSocket fetchPAC:%@", PACurl);
|
|
-
|
|
|
|
|
|
+
|
|
if ([PACurl isFileURL]) {
|
|
if ([PACurl isFileURL]) {
|
|
- NSError *nsError = nil;
|
|
|
|
|
|
+ NSError *error = nil;
|
|
NSString *script = [NSString stringWithContentsOfURL:PACurl
|
|
NSString *script = [NSString stringWithContentsOfURL:PACurl
|
|
usedEncoding:NULL
|
|
usedEncoding:NULL
|
|
- error:&nsError];
|
|
|
|
-
|
|
|
|
- if (nsError) {
|
|
|
|
|
|
+ error:&error];
|
|
|
|
+
|
|
|
|
+ if (error) {
|
|
[self _openConnection];
|
|
[self _openConnection];
|
|
- return;
|
|
|
|
|
|
+ } else {
|
|
|
|
+ [self _runPACScript:script];
|
|
}
|
|
}
|
|
- [self _runPACScript:script];
|
|
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
NSString *scheme = [PACurl.scheme lowercaseString];
|
|
NSString *scheme = [PACurl.scheme lowercaseString];
|
|
if (![scheme isEqualToString:@"http"] && ![scheme isEqualToString:@"https"]) {
|
|
if (![scheme isEqualToString:@"http"] && ![scheme isEqualToString:@"https"]) {
|
|
// Don't know how to read data from this URL, we'll have to give up
|
|
// Don't know how to read data from this URL, we'll have to give up
|
|
@@ -210,7 +226,7 @@ typedef void (^SRProxyConnectionCompletion)(NSError *error, NSInputStream *readS
|
|
} else {
|
|
} else {
|
|
[weakSelf _openConnection];
|
|
[weakSelf _openConnection];
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
}];
|
|
}];
|
|
[task resume];
|
|
[task resume];
|
|
}
|
|
}
|
|
@@ -226,19 +242,19 @@ typedef void (^SRProxyConnectionCompletion)(NSError *error, NSInputStream *readS
|
|
// Work around <rdar://problem/5530166>. This dummy call to
|
|
// Work around <rdar://problem/5530166>. This dummy call to
|
|
// CFNetworkCopyProxiesForURL initialise some state within CFNetwork
|
|
// CFNetworkCopyProxiesForURL initialise some state within CFNetwork
|
|
// that is required by CFNetworkCopyProxiesForAutoConfigurationScript.
|
|
// that is required by CFNetworkCopyProxiesForAutoConfigurationScript.
|
|
- NSDictionary *empty;
|
|
|
|
|
|
+ NSDictionary *empty = nil;
|
|
CFBridgingRelease(CFNetworkCopyProxiesForURL((__bridge CFURLRef)_url, (__bridge CFDictionaryRef)empty));
|
|
CFBridgingRelease(CFNetworkCopyProxiesForURL((__bridge CFURLRef)_url, (__bridge CFDictionaryRef)empty));
|
|
-
|
|
|
|
|
|
+
|
|
// Obtain the list of proxies by running the autoconfiguration script
|
|
// Obtain the list of proxies by running the autoconfiguration script
|
|
CFErrorRef err = NULL;
|
|
CFErrorRef err = NULL;
|
|
-
|
|
|
|
|
|
+
|
|
// CFNetworkCopyProxiesForAutoConfigurationScript doesn't understand ws:// or wss://
|
|
// CFNetworkCopyProxiesForAutoConfigurationScript doesn't understand ws:// or wss://
|
|
NSURL *httpURL;
|
|
NSURL *httpURL;
|
|
- if (_secure)
|
|
|
|
|
|
+ if (_connectionRequiresSSL)
|
|
httpURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@", _url.host]];
|
|
httpURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@", _url.host]];
|
|
else
|
|
else
|
|
httpURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@", _url.host]];
|
|
httpURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@", _url.host]];
|
|
-
|
|
|
|
|
|
+
|
|
NSArray *proxies = CFBridgingRelease(CFNetworkCopyProxiesForAutoConfigurationScript((__bridge CFStringRef)script,(__bridge CFURLRef)httpURL, &err));
|
|
NSArray *proxies = CFBridgingRelease(CFNetworkCopyProxiesForAutoConfigurationScript((__bridge CFStringRef)script,(__bridge CFURLRef)httpURL, &err));
|
|
if (!err && [proxies count] > 0) {
|
|
if (!err && [proxies count] > 0) {
|
|
NSDictionary *settings = [proxies objectAtIndex:0];
|
|
NSDictionary *settings = [proxies objectAtIndex:0];
|
|
@@ -248,10 +264,10 @@ typedef void (^SRProxyConnectionCompletion)(NSError *error, NSInputStream *readS
|
|
[self _openConnection];
|
|
[self _openConnection];
|
|
}
|
|
}
|
|
|
|
|
|
-- (void)_openConnection;
|
|
|
|
|
|
+- (void)_openConnection
|
|
{
|
|
{
|
|
[self _initializeStreams];
|
|
[self _initializeStreams];
|
|
-
|
|
|
|
|
|
+
|
|
[self.inputStream scheduleInRunLoop:[NSRunLoop SR_networkRunLoop]
|
|
[self.inputStream scheduleInRunLoop:[NSRunLoop SR_networkRunLoop]
|
|
forMode:NSDefaultRunLoopMode];
|
|
forMode:NSDefaultRunLoopMode];
|
|
//[self.outputStream scheduleInRunLoop:[NSRunLoop SR_networkRunLoop]
|
|
//[self.outputStream scheduleInRunLoop:[NSRunLoop SR_networkRunLoop]
|
|
@@ -260,33 +276,26 @@ typedef void (^SRProxyConnectionCompletion)(NSError *error, NSInputStream *readS
|
|
[self.inputStream open];
|
|
[self.inputStream open];
|
|
}
|
|
}
|
|
|
|
|
|
-- (void)_initializeStreams;
|
|
|
|
|
|
+- (void)_initializeStreams
|
|
{
|
|
{
|
|
assert(_url.port.unsignedIntValue <= UINT32_MAX);
|
|
assert(_url.port.unsignedIntValue <= UINT32_MAX);
|
|
uint32_t port = _url.port.unsignedIntValue;
|
|
uint32_t port = _url.port.unsignedIntValue;
|
|
if (port == 0) {
|
|
if (port == 0) {
|
|
- if (!_secure) {
|
|
|
|
- port = 80;
|
|
|
|
- } else {
|
|
|
|
- port = 443;
|
|
|
|
- }
|
|
|
|
|
|
+ port = (_connectionRequiresSSL ? 443 : 80);
|
|
}
|
|
}
|
|
NSString *host = _url.host;
|
|
NSString *host = _url.host;
|
|
-
|
|
|
|
|
|
+
|
|
if (_httpProxyHost) {
|
|
if (_httpProxyHost) {
|
|
host = _httpProxyHost;
|
|
host = _httpProxyHost;
|
|
- if (_httpProxyPort)
|
|
|
|
- port = _httpProxyPort;
|
|
|
|
- else
|
|
|
|
- port = 80;
|
|
|
|
|
|
+ port = (_httpProxyPort ?: 80);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
CFReadStreamRef readStream = NULL;
|
|
CFReadStreamRef readStream = NULL;
|
|
CFWriteStreamRef writeStream = NULL;
|
|
CFWriteStreamRef writeStream = NULL;
|
|
-
|
|
|
|
|
|
+
|
|
SRProxyFastLog(@"ProxyConnect connect stream to %@:%u", host, port);
|
|
SRProxyFastLog(@"ProxyConnect connect stream to %@:%u", host, port);
|
|
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, port, &readStream, &writeStream);
|
|
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, port, &readStream, &writeStream);
|
|
-
|
|
|
|
|
|
+
|
|
self.outputStream = CFBridgingRelease(writeStream);
|
|
self.outputStream = CFBridgingRelease(writeStream);
|
|
self.inputStream = CFBridgingRelease(readStream);
|
|
self.inputStream = CFBridgingRelease(readStream);
|
|
|
|
|
|
@@ -322,28 +331,18 @@ typedef void (^SRProxyConnectionCompletion)(NSError *error, NSInputStream *readS
|
|
[self _didConnect];
|
|
[self _didConnect];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ } break;
|
|
case NSStreamEventErrorOccurred: {
|
|
case NSStreamEventErrorOccurred: {
|
|
[self _failWithError:aStream.streamError];
|
|
[self _failWithError:aStream.streamError];
|
|
- break;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ } break;
|
|
case NSStreamEventEndEncountered: {
|
|
case NSStreamEventEndEncountered: {
|
|
[self _failWithError:aStream.streamError];
|
|
[self _failWithError:aStream.streamError];
|
|
-
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ } break;
|
|
case NSStreamEventHasBytesAvailable: {
|
|
case NSStreamEventHasBytesAvailable: {
|
|
if (aStream == _inputStream) {
|
|
if (aStream == _inputStream) {
|
|
[self _processInputStream];
|
|
[self _processInputStream];
|
|
}
|
|
}
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ } break;
|
|
default:
|
|
default:
|
|
SRProxyFastLog(@"(default) %@", aStream);
|
|
SRProxyFastLog(@"(default) %@", aStream);
|
|
break;
|
|
break;
|
|
@@ -355,46 +354,41 @@ typedef void (^SRProxyConnectionCompletion)(NSError *error, NSInputStream *readS
|
|
SRProxyFastLog(@"Proxy Connected");
|
|
SRProxyFastLog(@"Proxy Connected");
|
|
uint32_t port = _url.port.unsignedIntValue;
|
|
uint32_t port = _url.port.unsignedIntValue;
|
|
if (port == 0) {
|
|
if (port == 0) {
|
|
- if (!_secure) {
|
|
|
|
- port = 80;
|
|
|
|
- } else {
|
|
|
|
- port = 443;
|
|
|
|
- }
|
|
|
|
|
|
+ port = (_connectionRequiresSSL ? 443 : 80);
|
|
}
|
|
}
|
|
// Send HTTP CONNECT Request
|
|
// Send HTTP CONNECT Request
|
|
NSString *connectRequestStr = [NSString stringWithFormat:@"CONNECT %@:%u HTTP/1.1\r\nHost: %@\r\nConnection: keep-alive\r\nProxy-Connection: keep-alive\r\n\r\n", _url.host, port, _url.host];
|
|
NSString *connectRequestStr = [NSString stringWithFormat:@"CONNECT %@:%u HTTP/1.1\r\nHost: %@\r\nConnection: keep-alive\r\nProxy-Connection: keep-alive\r\n\r\n", _url.host, port, _url.host];
|
|
-
|
|
|
|
- NSData *message = [connectRequestStr dataUsingEncoding:NSUTF8StringEncoding];
|
|
|
|
|
|
+
|
|
|
|
+ NSData *message = [connectRequestStr dataUsingEncoding:NSUTF8StringEncoding];
|
|
SRProxyFastLog(@"Proxy sending %@", connectRequestStr);
|
|
SRProxyFastLog(@"Proxy sending %@", connectRequestStr);
|
|
-
|
|
|
|
|
|
+
|
|
[self _writeData:message];
|
|
[self _writeData:message];
|
|
}
|
|
}
|
|
|
|
|
|
static size_t const SRProxyConnectBufferMaxSize = 4096;
|
|
static size_t const SRProxyConnectBufferMaxSize = 4096;
|
|
|
|
|
|
///handles the incoming bytes and sending them to the proper processing method
|
|
///handles the incoming bytes and sending them to the proper processing method
|
|
--(void) _processInputStream
|
|
|
|
|
|
+- (void)_processInputStream
|
|
{
|
|
{
|
|
NSMutableData *buf = [NSMutableData dataWithCapacity:SRProxyConnectBufferMaxSize];
|
|
NSMutableData *buf = [NSMutableData dataWithCapacity:SRProxyConnectBufferMaxSize];
|
|
uint8_t *buffer = buf.mutableBytes;
|
|
uint8_t *buffer = buf.mutableBytes;
|
|
- NSInteger length = [_inputStream read:buffer maxLength: SRProxyConnectBufferMaxSize];
|
|
|
|
-
|
|
|
|
- if (length <= 0)
|
|
|
|
|
|
+ NSInteger length = [_inputStream read:buffer maxLength:SRProxyConnectBufferMaxSize];
|
|
|
|
+
|
|
|
|
+ if (length <= 0) {
|
|
return;
|
|
return;
|
|
- BOOL process = NO;
|
|
|
|
- if (_inputQueue.count == 0)
|
|
|
|
- process = YES;
|
|
|
|
-
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ BOOL process = (_inputQueue.count == 0);
|
|
[_inputQueue addObject:[NSData dataWithBytes:buffer length:length]];
|
|
[_inputQueue addObject:[NSData dataWithBytes:buffer length:length]];
|
|
-
|
|
|
|
- if (process)
|
|
|
|
|
|
+
|
|
|
|
+ if (process) {
|
|
[self _dequeueInput];
|
|
[self _dequeueInput];
|
|
-
|
|
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
-///dequeue the incoming input so it is processed in order
|
|
|
|
|
|
+// dequeue the incoming input so it is processed in order
|
|
|
|
|
|
--(void) _dequeueInput
|
|
|
|
|
|
+- (void)_dequeueInput
|
|
{
|
|
{
|
|
while (_inputQueue.count > 0) {
|
|
while (_inputQueue.count > 0) {
|
|
NSData * data = _inputQueue[0];
|
|
NSData * data = _inputQueue[0];
|
|
@@ -403,12 +397,12 @@ static size_t const SRProxyConnectBufferMaxSize = 4096;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//handle checking the proxy connection status
|
|
//handle checking the proxy connection status
|
|
--(void) _proxyProcessHTTPResponseWithData:(NSData *)data
|
|
|
|
|
|
+- (void)_proxyProcessHTTPResponseWithData:(NSData *)data
|
|
{
|
|
{
|
|
if (_receivedHTTPHeaders == NULL) {
|
|
if (_receivedHTTPHeaders == NULL) {
|
|
_receivedHTTPHeaders = CFHTTPMessageCreateEmpty(NULL, NO);
|
|
_receivedHTTPHeaders = CFHTTPMessageCreateEmpty(NULL, NO);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
CFHTTPMessageAppendBytes(_receivedHTTPHeaders, (const UInt8 *)data.bytes, data.length);
|
|
CFHTTPMessageAppendBytes(_receivedHTTPHeaders, (const UInt8 *)data.bytes, data.length);
|
|
if (CFHTTPMessageIsHeaderComplete(_receivedHTTPHeaders)) {
|
|
if (CFHTTPMessageIsHeaderComplete(_receivedHTTPHeaders)) {
|
|
SRProxyFastLog(@"Finished reading headers %@", CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(_receivedHTTPHeaders)));
|
|
SRProxyFastLog(@"Finished reading headers %@", CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(_receivedHTTPHeaders)));
|
|
@@ -416,10 +410,10 @@ static size_t const SRProxyConnectBufferMaxSize = 4096;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-- (void)_proxyHTTPHeadersDidFinish;
|
|
|
|
|
|
+- (void)_proxyHTTPHeadersDidFinish
|
|
{
|
|
{
|
|
NSInteger responseCode = CFHTTPMessageGetResponseStatusCode(_receivedHTTPHeaders);
|
|
NSInteger responseCode = CFHTTPMessageGetResponseStatusCode(_receivedHTTPHeaders);
|
|
-
|
|
|
|
|
|
+
|
|
if (responseCode >= 299) {
|
|
if (responseCode >= 299) {
|
|
SRProxyFastLog(@"Connect to Proxy Request failed with response code %d", responseCode);
|
|
SRProxyFastLog(@"Connect to Proxy Request failed with response code %d", responseCode);
|
|
NSError *error = SRHTTPErrorWithCodeDescription(responseCode, 2132,
|
|
NSError *error = SRHTTPErrorWithCodeDescription(responseCode, 2132,
|
|
@@ -432,23 +426,26 @@ static size_t const SRProxyConnectBufferMaxSize = 4096;
|
|
[self _didConnect];
|
|
[self _didConnect];
|
|
}
|
|
}
|
|
|
|
|
|
-#define timeout 5
|
|
|
|
--(void)_writeData:(NSData *)data;
|
|
|
|
|
|
+static NSTimeInterval const SRProxyConnectWriteTimeout = 5.0;
|
|
|
|
+
|
|
|
|
+- (void)_writeData:(NSData *)data
|
|
{
|
|
{
|
|
const uint8_t * bytes = data.bytes;
|
|
const uint8_t * bytes = data.bytes;
|
|
- __block NSInteger out = timeout * 1000000; //wait 5 seconds before giving up
|
|
|
|
- __weak typeof(self) weakSelf = self;
|
|
|
|
|
|
+ __block NSInteger timeout = SRProxyConnectWriteTimeout * 1000000; // wait timeout before giving up
|
|
|
|
+ __weak typeof(self) wself = self;
|
|
[_writeQueue addOperationWithBlock:^() {
|
|
[_writeQueue addOperationWithBlock:^() {
|
|
- if (!weakSelf)
|
|
|
|
|
|
+ if (!wself) {
|
|
return;
|
|
return;
|
|
- NSOutputStream *outStream = weakSelf.outputStream;
|
|
|
|
- if (!outStream)
|
|
|
|
|
|
+ }
|
|
|
|
+ NSOutputStream *outStream = wself.outputStream;
|
|
|
|
+ if (!outStream) {
|
|
return;
|
|
return;
|
|
- while ( ![outStream hasSpaceAvailable]) {
|
|
|
|
|
|
+ }
|
|
|
|
+ while (![outStream hasSpaceAvailable]) {
|
|
usleep(100); //wait until the socket is ready
|
|
usleep(100); //wait until the socket is ready
|
|
- out -= 100;
|
|
|
|
- if (out < 0) {
|
|
|
|
- NSError *error = SRHTTPErrorWithCodeDescription(408, 2132,@"Proxy timeout");
|
|
|
|
|
|
+ timeout -= 100;
|
|
|
|
+ if (timeout < 0) {
|
|
|
|
+ NSError *error = SRHTTPErrorWithCodeDescription(408, 2132, @"Proxy timeout");
|
|
[self _failWithError:error];
|
|
[self _failWithError:error];
|
|
} else if (outStream.streamError != nil) {
|
|
} else if (outStream.streamError != nil) {
|
|
[self _failWithError:outStream.streamError];
|
|
[self _failWithError:outStream.streamError];
|
|
@@ -465,11 +462,11 @@ static inline void SRProxyFastLog(NSString *format, ...) {
|
|
#ifdef SRPROXY_ENABLE_LOG
|
|
#ifdef SRPROXY_ENABLE_LOG
|
|
__block va_list arg_list;
|
|
__block va_list arg_list;
|
|
va_start (arg_list, format);
|
|
va_start (arg_list, format);
|
|
-
|
|
|
|
|
|
+
|
|
NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list];
|
|
NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list];
|
|
-
|
|
|
|
|
|
+
|
|
va_end(arg_list);
|
|
va_end(arg_list);
|
|
-
|
|
|
|
|
|
+
|
|
NSLog(@"[Proxy] %@", formattedString);
|
|
NSLog(@"[Proxy] %@", formattedString);
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|