SRWebSocket.m 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918
  1. //
  2. // Copyright 2012 Square Inc.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. #import "SRWebSocket.h"
  17. #if TARGET_OS_IPHONE
  18. #define HAS_ICU
  19. #endif
  20. #ifdef HAS_ICU
  21. #import <unicode/utf8.h>
  22. #endif
  23. #if TARGET_OS_IPHONE
  24. #import <Endian.h>
  25. #else
  26. #import <CoreServices/CoreServices.h>
  27. #endif
  28. #import <CommonCrypto/CommonDigest.h>
  29. #import <Security/SecRandom.h>
  30. #if OS_OBJECT_USE_OBJC_RETAIN_RELEASE
  31. #define sr_dispatch_retain(x)
  32. #define sr_dispatch_release(x)
  33. #define maybe_bridge(x) ((__bridge void *) x)
  34. #else
  35. #define sr_dispatch_retain(x) dispatch_retain(x)
  36. #define sr_dispatch_release(x) dispatch_release(x)
  37. #define maybe_bridge(x) (x)
  38. #endif
  39. #if !__has_feature(objc_arc)
  40. #error SocketRocket must be compiled with ARC enabled
  41. #endif
  42. typedef enum {
  43. SROpCodeTextFrame = 0x1,
  44. SROpCodeBinaryFrame = 0x2,
  45. // 3-7 reserved.
  46. SROpCodeConnectionClose = 0x8,
  47. SROpCodePing = 0x9,
  48. SROpCodePong = 0xA,
  49. // B-F reserved.
  50. } SROpCode;
  51. typedef struct {
  52. BOOL fin;
  53. // BOOL rsv1;
  54. // BOOL rsv2;
  55. // BOOL rsv3;
  56. uint8_t opcode;
  57. BOOL masked;
  58. uint64_t payload_length;
  59. } frame_header;
  60. static NSString *const SRWebSocketAppendToSecKeyString = @"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
  61. static inline int32_t validate_dispatch_data_partial_string(NSData *data);
  62. static inline void SRFastLog(NSString *format, ...);
  63. @interface NSData (SRWebSocket)
  64. - (NSString *)stringBySHA1ThenBase64Encoding;
  65. @end
  66. @interface NSString (SRWebSocket)
  67. - (NSString *)stringBySHA1ThenBase64Encoding;
  68. @end
  69. @interface NSURL (SRWebSocket)
  70. // The origin isn't really applicable for a native application.
  71. // So instead, just map ws -> http and wss -> https.
  72. - (NSString *)SR_origin;
  73. @end
  74. @interface _SRRunLoopThread : NSThread
  75. @property (nonatomic, readonly) NSRunLoop *runLoop;
  76. @end
  77. static NSString *newSHA1String(const char *bytes, size_t length) {
  78. uint8_t md[CC_SHA1_DIGEST_LENGTH];
  79. assert(length >= 0);
  80. assert(length <= UINT32_MAX);
  81. CC_SHA1(bytes, (CC_LONG)length, md);
  82. NSData *data = [NSData dataWithBytes:md length:CC_SHA1_DIGEST_LENGTH];
  83. if ([data respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
  84. return [data base64EncodedStringWithOptions:0];
  85. }
  86. #pragma clang diagnostic push
  87. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  88. return [data base64Encoding];
  89. #pragma clang diagnostic pop
  90. }
  91. @implementation NSData (SRWebSocket)
  92. - (NSString *)stringBySHA1ThenBase64Encoding;
  93. {
  94. return newSHA1String(self.bytes, self.length);
  95. }
  96. @end
  97. @implementation NSString (SRWebSocket)
  98. - (NSString *)stringBySHA1ThenBase64Encoding;
  99. {
  100. return newSHA1String(self.UTF8String, self.length);
  101. }
  102. @end
  103. NSString *const SRWebSocketErrorDomain = @"SRWebSocketErrorDomain";
  104. NSString *const SRHTTPResponseErrorKey = @"HTTPResponseStatusCode";
  105. // Returns number of bytes consumed. Returning 0 means you didn't match.
  106. // Sends bytes to callback handler;
  107. typedef size_t (^stream_scanner)(NSData *collected_data);
  108. typedef void (^data_callback)(SRWebSocket *webSocket, NSData *data);
  109. @interface SRIOConsumer : NSObject {
  110. stream_scanner _scanner;
  111. data_callback _handler;
  112. size_t _bytesNeeded;
  113. BOOL _readToCurrentFrame;
  114. BOOL _unmaskBytes;
  115. }
  116. @property (nonatomic, copy, readonly) stream_scanner consumer;
  117. @property (nonatomic, copy, readonly) data_callback handler;
  118. @property (nonatomic, assign) size_t bytesNeeded;
  119. @property (nonatomic, assign, readonly) BOOL readToCurrentFrame;
  120. @property (nonatomic, assign, readonly) BOOL unmaskBytes;
  121. @end
  122. // This class is not thread-safe, and is expected to always be run on the same queue.
  123. @interface SRIOConsumerPool : NSObject
  124. - (id)initWithBufferCapacity:(NSUInteger)poolSize;
  125. - (SRIOConsumer *)consumerWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes;
  126. - (void)returnConsumer:(SRIOConsumer *)consumer;
  127. @end
  128. @interface SRWebSocket () <NSStreamDelegate>
  129. @property (nonatomic) SRReadyState readyState;
  130. @property (nonatomic) NSOperationQueue *delegateOperationQueue;
  131. @property (nonatomic) dispatch_queue_t delegateDispatchQueue;
  132. // Specifies whether SSL trust chain should NOT be evaluated.
  133. // By default this flag is set to NO, meaning only secure SSL connections are allowed.
  134. // For DEBUG builds this flag is ignored, and SSL connections are allowed regardless
  135. // of the certificate trust configuration
  136. @property (nonatomic, readwrite) BOOL allowsUntrustedSSLCertificates;
  137. @end
  138. @implementation SRWebSocket {
  139. NSInteger _webSocketVersion;
  140. NSOperationQueue *_delegateOperationQueue;
  141. dispatch_queue_t _delegateDispatchQueue;
  142. dispatch_queue_t _workQueue;
  143. NSMutableArray *_consumers;
  144. NSInputStream *_inputStream;
  145. NSOutputStream *_outputStream;
  146. NSMutableData *_readBuffer;
  147. NSUInteger _readBufferOffset;
  148. NSMutableData *_outputBuffer;
  149. NSUInteger _outputBufferOffset;
  150. uint8_t _currentFrameOpcode;
  151. size_t _currentFrameCount;
  152. size_t _readOpCount;
  153. uint32_t _currentStringScanPosition;
  154. NSMutableData *_currentFrameData;
  155. NSString *_closeReason;
  156. NSString *_secKey;
  157. NSString *_basicAuthorizationString;
  158. BOOL _pinnedCertFound;
  159. uint8_t _currentReadMaskKey[4];
  160. size_t _currentReadMaskOffset;
  161. BOOL _consumerStopped;
  162. BOOL _closeWhenFinishedWriting;
  163. BOOL _failed;
  164. BOOL _secure;
  165. NSURLRequest *_urlRequest;
  166. BOOL _sentClose;
  167. BOOL _didFail;
  168. BOOL _cleanupScheduled;
  169. int _closeCode;
  170. BOOL _isPumping;
  171. NSMutableSet *_scheduledRunloops;
  172. // We use this to retain ourselves.
  173. __strong SRWebSocket *_selfRetain;
  174. NSArray *_requestedProtocols;
  175. SRIOConsumerPool *_consumerPool;
  176. }
  177. @synthesize delegate = _delegate;
  178. @synthesize url = _url;
  179. @synthesize readyState = _readyState;
  180. @synthesize protocol = _protocol;
  181. static __strong NSData *CRLFCRLF;
  182. + (void)initialize;
  183. {
  184. CRLFCRLF = [[NSData alloc] initWithBytes:"\r\n\r\n" length:4];
  185. }
  186. - (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates;
  187. {
  188. self = [super init];
  189. if (self) {
  190. assert(request.URL);
  191. _url = request.URL;
  192. _urlRequest = request;
  193. _allowsUntrustedSSLCertificates = allowsUntrustedSSLCertificates;
  194. _requestedProtocols = [protocols copy];
  195. [self _SR_commonInit];
  196. }
  197. return self;
  198. }
  199. - (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols;
  200. {
  201. return [self initWithURLRequest:request protocols:protocols allowsUntrustedSSLCertificates:NO];
  202. }
  203. - (id)initWithURLRequest:(NSURLRequest *)request;
  204. {
  205. return [self initWithURLRequest:request protocols:nil];
  206. }
  207. - (id)initWithURL:(NSURL *)url;
  208. {
  209. return [self initWithURL:url protocols:nil];
  210. }
  211. - (id)initWithURL:(NSURL *)url protocols:(NSArray *)protocols;
  212. {
  213. NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
  214. return [self initWithURLRequest:request protocols:protocols];
  215. }
  216. - (id)initWithURL:(NSURL *)url protocols:(NSArray *)protocols allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates;
  217. {
  218. NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
  219. return [self initWithURLRequest:request protocols:protocols allowsUntrustedSSLCertificates:allowsUntrustedSSLCertificates];
  220. }
  221. - (void)_SR_commonInit;
  222. {
  223. NSString *scheme = _url.scheme.lowercaseString;
  224. assert([scheme isEqualToString:@"ws"] || [scheme isEqualToString:@"http"] || [scheme isEqualToString:@"wss"] || [scheme isEqualToString:@"https"]);
  225. if ([scheme isEqualToString:@"wss"] || [scheme isEqualToString:@"https"]) {
  226. _secure = YES;
  227. }
  228. _readyState = SR_CONNECTING;
  229. _consumerStopped = YES;
  230. _webSocketVersion = 13;
  231. _workQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
  232. // Going to set a specific on the queue so we can validate we're on the work queue
  233. dispatch_queue_set_specific(_workQueue, (__bridge void *)self, maybe_bridge(_workQueue), NULL);
  234. _delegateDispatchQueue = dispatch_get_main_queue();
  235. sr_dispatch_retain(_delegateDispatchQueue);
  236. _readBuffer = [[NSMutableData alloc] init];
  237. _outputBuffer = [[NSMutableData alloc] init];
  238. _currentFrameData = [[NSMutableData alloc] init];
  239. _consumers = [[NSMutableArray alloc] init];
  240. _consumerPool = [[SRIOConsumerPool alloc] init];
  241. _scheduledRunloops = [[NSMutableSet alloc] init];
  242. [self _initializeStreams];
  243. // default handlers
  244. }
  245. - (void)assertOnWorkQueue;
  246. {
  247. assert(dispatch_get_specific((__bridge void *)self) == maybe_bridge(_workQueue));
  248. }
  249. - (void)dealloc
  250. {
  251. _inputStream.delegate = nil;
  252. _outputStream.delegate = nil;
  253. [_inputStream close];
  254. [_outputStream close];
  255. if (_workQueue) {
  256. sr_dispatch_release(_workQueue);
  257. _workQueue = NULL;
  258. }
  259. if (_receivedHTTPHeaders) {
  260. CFRelease(_receivedHTTPHeaders);
  261. _receivedHTTPHeaders = NULL;
  262. }
  263. if (_delegateDispatchQueue) {
  264. sr_dispatch_release(_delegateDispatchQueue);
  265. _delegateDispatchQueue = NULL;
  266. }
  267. }
  268. #ifndef NDEBUG
  269. - (void)setReadyState:(SRReadyState)aReadyState;
  270. {
  271. assert(aReadyState > _readyState);
  272. _readyState = aReadyState;
  273. }
  274. #endif
  275. - (void)open;
  276. {
  277. assert(_url);
  278. NSAssert(_readyState == SR_CONNECTING, @"Cannot call -(void)open on SRWebSocket more than once");
  279. _selfRetain = self;
  280. if (_urlRequest.timeoutInterval > 0)
  281. {
  282. dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, _urlRequest.timeoutInterval * NSEC_PER_SEC);
  283. dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
  284. if (self.readyState == SR_CONNECTING)
  285. [self _failWithError:[NSError errorWithDomain:@"com.squareup.SocketRocket" code:504 userInfo:@{NSLocalizedDescriptionKey: @"Timeout Connecting to Server"}]];
  286. });
  287. }
  288. [self openConnection];
  289. }
  290. // Calls block on delegate queue
  291. - (void)_performDelegateBlock:(dispatch_block_t)block;
  292. {
  293. if (_delegateOperationQueue) {
  294. [_delegateOperationQueue addOperationWithBlock:block];
  295. } else {
  296. assert(_delegateDispatchQueue);
  297. dispatch_async(_delegateDispatchQueue, block);
  298. }
  299. }
  300. - (void)setDelegateDispatchQueue:(dispatch_queue_t)queue;
  301. {
  302. if (queue) {
  303. sr_dispatch_retain(queue);
  304. }
  305. if (_delegateDispatchQueue) {
  306. sr_dispatch_release(_delegateDispatchQueue);
  307. }
  308. _delegateDispatchQueue = queue;
  309. }
  310. - (BOOL)_checkHandshake:(CFHTTPMessageRef)httpMessage;
  311. {
  312. NSString *acceptHeader = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(httpMessage, CFSTR("Sec-WebSocket-Accept")));
  313. if (acceptHeader == nil) {
  314. return NO;
  315. }
  316. NSString *concattedString = [_secKey stringByAppendingString:SRWebSocketAppendToSecKeyString];
  317. NSString *expectedAccept = [concattedString stringBySHA1ThenBase64Encoding];
  318. return [acceptHeader isEqualToString:expectedAccept];
  319. }
  320. - (void)_HTTPHeadersDidFinish;
  321. {
  322. NSInteger responseCode = CFHTTPMessageGetResponseStatusCode(_receivedHTTPHeaders);
  323. if (responseCode >= 400) {
  324. SRFastLog(@"Request failed with response code %d", responseCode);
  325. [self _failWithError:[NSError errorWithDomain:SRWebSocketErrorDomain code:2132 userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"received bad response code from server %ld", (long)responseCode], SRHTTPResponseErrorKey:@(responseCode)}]];
  326. return;
  327. }
  328. if(![self _checkHandshake:_receivedHTTPHeaders]) {
  329. [self _failWithError:[NSError errorWithDomain:SRWebSocketErrorDomain code:2133 userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Invalid Sec-WebSocket-Accept response"] forKey:NSLocalizedDescriptionKey]]];
  330. return;
  331. }
  332. NSString *negotiatedProtocol = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(_receivedHTTPHeaders, CFSTR("Sec-WebSocket-Protocol")));
  333. if (negotiatedProtocol) {
  334. // Make sure we requested the protocol
  335. if ([_requestedProtocols indexOfObject:negotiatedProtocol] == NSNotFound) {
  336. [self _failWithError:[NSError errorWithDomain:SRWebSocketErrorDomain code:2133 userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Server specified Sec-WebSocket-Protocol that wasn't requested"] forKey:NSLocalizedDescriptionKey]]];
  337. return;
  338. }
  339. _protocol = negotiatedProtocol;
  340. }
  341. self.readyState = SR_OPEN;
  342. if (!_didFail) {
  343. [self _readFrameNew];
  344. }
  345. [self _performDelegateBlock:^{
  346. if ([self.delegate respondsToSelector:@selector(webSocketDidOpen:)]) {
  347. [self.delegate webSocketDidOpen:self];
  348. };
  349. }];
  350. }
  351. - (void)_readHTTPHeader;
  352. {
  353. if (_receivedHTTPHeaders == NULL) {
  354. _receivedHTTPHeaders = CFHTTPMessageCreateEmpty(NULL, NO);
  355. }
  356. [self _readUntilHeaderCompleteWithCallback:^(SRWebSocket *self, NSData *data) {
  357. CFHTTPMessageAppendBytes(_receivedHTTPHeaders, (const UInt8 *)data.bytes, data.length);
  358. if (CFHTTPMessageIsHeaderComplete(_receivedHTTPHeaders)) {
  359. SRFastLog(@"Finished reading headers %@", CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(_receivedHTTPHeaders)));
  360. [self _HTTPHeadersDidFinish];
  361. } else {
  362. [self _readHTTPHeader];
  363. }
  364. }];
  365. }
  366. - (void)didConnect;
  367. {
  368. SRFastLog(@"Connected");
  369. CFHTTPMessageRef request = CFHTTPMessageCreateRequest(NULL, CFSTR("GET"), (__bridge CFURLRef)_url, kCFHTTPVersion1_1);
  370. // Set host first so it defaults
  371. CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Host"), (__bridge CFStringRef)(_url.port ? [NSString stringWithFormat:@"%@:%@", _url.host, _url.port] : _url.host));
  372. NSMutableData *keyBytes = [[NSMutableData alloc] initWithLength:16];
  373. SecRandomCopyBytes(kSecRandomDefault, keyBytes.length, keyBytes.mutableBytes);
  374. if ([keyBytes respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
  375. _secKey = [keyBytes base64EncodedStringWithOptions:0];
  376. } else {
  377. #pragma clang diagnostic push
  378. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  379. _secKey = [keyBytes base64Encoding];
  380. #pragma clang diagnostic pop
  381. }
  382. assert([_secKey length] == 24);
  383. // Apply cookies if any have been provided
  384. NSDictionary * cookies = [NSHTTPCookie requestHeaderFieldsWithCookies:[self requestCookies]];
  385. for (NSString * cookieKey in cookies) {
  386. NSString * cookieValue = [cookies objectForKey:cookieKey];
  387. if ([cookieKey length] && [cookieValue length]) {
  388. CFHTTPMessageSetHeaderFieldValue(request, (__bridge CFStringRef)cookieKey, (__bridge CFStringRef)cookieValue);
  389. }
  390. }
  391. // set header for http basic auth
  392. if (_url.user.length && _url.password.length) {
  393. NSData *userAndPassword = [[NSString stringWithFormat:@"%@:%@", _url.user, _url.password] dataUsingEncoding:NSUTF8StringEncoding];
  394. NSString *userAndPasswordBase64Encoded;
  395. if ([keyBytes respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
  396. userAndPasswordBase64Encoded = [userAndPassword base64EncodedStringWithOptions:0];
  397. } else {
  398. #pragma clang diagnostic push
  399. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  400. userAndPasswordBase64Encoded = [userAndPassword base64Encoding];
  401. #pragma clang diagnostic pop
  402. }
  403. _basicAuthorizationString = [NSString stringWithFormat:@"Basic %@", userAndPasswordBase64Encoded];
  404. CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Authorization"), (__bridge CFStringRef)_basicAuthorizationString);
  405. }
  406. CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Upgrade"), CFSTR("websocket"));
  407. CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Connection"), CFSTR("Upgrade"));
  408. CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Key"), (__bridge CFStringRef)_secKey);
  409. CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Version"), (__bridge CFStringRef)[NSString stringWithFormat:@"%ld", (long)_webSocketVersion]);
  410. CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Origin"), (__bridge CFStringRef)_url.SR_origin);
  411. if (_requestedProtocols) {
  412. CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Protocol"), (__bridge CFStringRef)[_requestedProtocols componentsJoinedByString:@", "]);
  413. }
  414. [_urlRequest.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
  415. CFHTTPMessageSetHeaderFieldValue(request, (__bridge CFStringRef)key, (__bridge CFStringRef)obj);
  416. }];
  417. NSData *message = CFBridgingRelease(CFHTTPMessageCopySerializedMessage(request));
  418. CFRelease(request);
  419. [self _writeData:message];
  420. [self _readHTTPHeader];
  421. }
  422. - (void)_initializeStreams;
  423. {
  424. assert(_url.port.unsignedIntValue <= UINT32_MAX);
  425. uint32_t port = _url.port.unsignedIntValue;
  426. if (port == 0) {
  427. if (!_secure) {
  428. port = 80;
  429. } else {
  430. port = 443;
  431. }
  432. }
  433. NSString *host = _url.host;
  434. CFReadStreamRef readStream = NULL;
  435. CFWriteStreamRef writeStream = NULL;
  436. CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, port, &readStream, &writeStream);
  437. _outputStream = CFBridgingRelease(writeStream);
  438. _inputStream = CFBridgingRelease(readStream);
  439. _inputStream.delegate = self;
  440. _outputStream.delegate = self;
  441. }
  442. - (void)_updateSecureStreamOptions;
  443. {
  444. if (_secure) {
  445. NSMutableDictionary *SSLOptions = [[NSMutableDictionary alloc] init];
  446. [_outputStream setProperty:(__bridge id)kCFStreamSocketSecurityLevelNegotiatedSSL forKey:(__bridge id)kCFStreamPropertySocketSecurityLevel];
  447. // If we're using pinned certs, don't validate the certificate chain
  448. if ([_urlRequest SR_SSLPinnedCertificates].count) {
  449. [SSLOptions setValue:@NO forKey:(__bridge id)kCFStreamSSLValidatesCertificateChain];
  450. }
  451. #if DEBUG
  452. self.allowsUntrustedSSLCertificates = YES;
  453. #endif
  454. if (self.allowsUntrustedSSLCertificates) {
  455. [SSLOptions setValue:@NO forKey:(__bridge id)kCFStreamSSLValidatesCertificateChain];
  456. SRFastLog(@"Allowing connection to any root cert");
  457. }
  458. [_outputStream setProperty:SSLOptions
  459. forKey:(__bridge id)kCFStreamPropertySSLSettings];
  460. }
  461. _inputStream.delegate = self;
  462. _outputStream.delegate = self;
  463. [self setupNetworkServiceType:_urlRequest.networkServiceType];
  464. }
  465. - (void)setupNetworkServiceType:(NSURLRequestNetworkServiceType)requestNetworkServiceType
  466. {
  467. NSString *networkServiceType;
  468. switch (requestNetworkServiceType) {
  469. case NSURLNetworkServiceTypeDefault:
  470. break;
  471. case NSURLNetworkServiceTypeVoIP: {
  472. networkServiceType = NSStreamNetworkServiceTypeVoIP;
  473. #if TARGET_OS_IPHONE && __IPHONE_9_0
  474. if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_8_3) {
  475. static dispatch_once_t predicate;
  476. dispatch_once(&predicate, ^{
  477. HLog(@"SocketRocket: %@ - this service type is deprecated in favor of using PushKit for VoIP control", networkServiceType);
  478. });
  479. }
  480. #endif
  481. break;
  482. }
  483. case NSURLNetworkServiceTypeVideo:
  484. networkServiceType = NSStreamNetworkServiceTypeVideo;
  485. break;
  486. case NSURLNetworkServiceTypeBackground:
  487. networkServiceType = NSStreamNetworkServiceTypeBackground;
  488. break;
  489. case NSURLNetworkServiceTypeVoice:
  490. networkServiceType = NSStreamNetworkServiceTypeVoice;
  491. break;
  492. }
  493. if (networkServiceType != nil) {
  494. [_inputStream setProperty:networkServiceType forKey:NSStreamNetworkServiceType];
  495. [_outputStream setProperty:networkServiceType forKey:NSStreamNetworkServiceType];
  496. }
  497. }
  498. - (void)openConnection;
  499. {
  500. [self _updateSecureStreamOptions];
  501. if (!_scheduledRunloops.count) {
  502. [self scheduleInRunLoop:[NSRunLoop SR_networkRunLoop] forMode:NSDefaultRunLoopMode];
  503. }
  504. [_outputStream open];
  505. [_inputStream open];
  506. }
  507. - (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
  508. {
  509. [_outputStream scheduleInRunLoop:aRunLoop forMode:mode];
  510. [_inputStream scheduleInRunLoop:aRunLoop forMode:mode];
  511. [_scheduledRunloops addObject:@[aRunLoop, mode]];
  512. }
  513. - (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
  514. {
  515. [_outputStream removeFromRunLoop:aRunLoop forMode:mode];
  516. [_inputStream removeFromRunLoop:aRunLoop forMode:mode];
  517. [_scheduledRunloops removeObject:@[aRunLoop, mode]];
  518. }
  519. - (void)close;
  520. {
  521. [self closeWithCode:SRStatusCodeNormal reason:nil];
  522. }
  523. - (void)closeWithCode:(NSInteger)code reason:(NSString *)reason;
  524. {
  525. assert(code);
  526. dispatch_async(_workQueue, ^{
  527. if (self.readyState == SR_CLOSING || self.readyState == SR_CLOSED) {
  528. return;
  529. }
  530. BOOL wasConnecting = self.readyState == SR_CONNECTING;
  531. self.readyState = SR_CLOSING;
  532. SRFastLog(@"Closing with code %d reason %@", code, reason);
  533. if (wasConnecting) {
  534. [self closeConnection];
  535. return;
  536. }
  537. size_t maxMsgSize = [reason maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding];
  538. NSMutableData *mutablePayload = [[NSMutableData alloc] initWithLength:sizeof(uint16_t) + maxMsgSize];
  539. NSData *payload = mutablePayload;
  540. ((uint16_t *)mutablePayload.mutableBytes)[0] = EndianU16_BtoN(code);
  541. if (reason) {
  542. NSRange remainingRange = {0};
  543. NSUInteger usedLength = 0;
  544. BOOL success = [reason getBytes:(char *)mutablePayload.mutableBytes + sizeof(uint16_t) maxLength:payload.length - sizeof(uint16_t) usedLength:&usedLength encoding:NSUTF8StringEncoding options:NSStringEncodingConversionExternalRepresentation range:NSMakeRange(0, reason.length) remainingRange:&remainingRange];
  545. #pragma unused (success)
  546. assert(success);
  547. assert(remainingRange.length == 0);
  548. if (usedLength != maxMsgSize) {
  549. payload = [payload subdataWithRange:NSMakeRange(0, usedLength + sizeof(uint16_t))];
  550. }
  551. }
  552. [self _sendFrameWithOpcode:SROpCodeConnectionClose data:payload];
  553. });
  554. }
  555. - (void)_closeWithProtocolError:(NSString *)message;
  556. {
  557. // Need to shunt this on the _callbackQueue first to see if they received any messages
  558. [self _performDelegateBlock:^{
  559. [self closeWithCode:SRStatusCodeProtocolError reason:message];
  560. dispatch_async(_workQueue, ^{
  561. [self closeConnection];
  562. });
  563. }];
  564. }
  565. - (void)_failWithError:(NSError *)error;
  566. {
  567. dispatch_async(_workQueue, ^{
  568. if (self.readyState != SR_CLOSED) {
  569. _failed = YES;
  570. [self _performDelegateBlock:^{
  571. if ([self.delegate respondsToSelector:@selector(webSocket:didFailWithError:)]) {
  572. [self.delegate webSocket:self didFailWithError:error];
  573. }
  574. }];
  575. self.readyState = SR_CLOSED;
  576. SRFastLog(@"Failing with error %@", error.localizedDescription);
  577. [self closeConnection];
  578. [self _scheduleCleanup];
  579. }
  580. });
  581. }
  582. - (void)_writeData:(NSData *)data;
  583. {
  584. [self assertOnWorkQueue];
  585. if (_closeWhenFinishedWriting) {
  586. return;
  587. }
  588. [_outputBuffer appendData:data];
  589. [self _pumpWriting];
  590. }
  591. - (void)send:(id)data;
  592. {
  593. NSAssert(self.readyState != SR_CONNECTING, @"Invalid State: Cannot call send: until connection is open");
  594. // TODO: maybe not copy this for performance
  595. data = [data copy];
  596. dispatch_async(_workQueue, ^{
  597. if ([data isKindOfClass:[NSString class]]) {
  598. [self _sendFrameWithOpcode:SROpCodeTextFrame data:[(NSString *)data dataUsingEncoding:NSUTF8StringEncoding]];
  599. } else if ([data isKindOfClass:[NSData class]]) {
  600. [self _sendFrameWithOpcode:SROpCodeBinaryFrame data:data];
  601. } else if (data == nil) {
  602. [self _sendFrameWithOpcode:SROpCodeTextFrame data:data];
  603. } else {
  604. assert(NO);
  605. }
  606. });
  607. }
  608. - (void)sendPing:(NSData *)data;
  609. {
  610. NSAssert(self.readyState == SR_OPEN, @"Invalid State: Cannot call send: until connection is open");
  611. // TODO: maybe not copy this for performance
  612. data = [data copy] ?: [NSData data]; // It's okay for a ping to be empty
  613. dispatch_async(_workQueue, ^{
  614. [self _sendFrameWithOpcode:SROpCodePing data:data];
  615. });
  616. }
  617. - (void)handlePing:(NSData *)pingData;
  618. {
  619. // Need to pingpong this off _callbackQueue first to make sure messages happen in order
  620. [self _performDelegateBlock:^{
  621. dispatch_async(_workQueue, ^{
  622. [self _sendFrameWithOpcode:SROpCodePong data:pingData];
  623. });
  624. }];
  625. }
  626. - (void)handlePong:(NSData *)pongData;
  627. {
  628. SRFastLog(@"Received pong");
  629. [self _performDelegateBlock:^{
  630. if ([self.delegate respondsToSelector:@selector(webSocket:didReceivePong:)]) {
  631. [self.delegate webSocket:self didReceivePong:pongData];
  632. }
  633. }];
  634. }
  635. - (void)_handleMessage:(id)message
  636. {
  637. SRFastLog(@"Received message");
  638. [self _performDelegateBlock:^{
  639. [self.delegate webSocket:self didReceiveMessage:message];
  640. }];
  641. }
  642. static inline BOOL closeCodeIsValid(int closeCode) {
  643. if (closeCode < 1000) {
  644. return NO;
  645. }
  646. if (closeCode >= 1000 && closeCode <= 1011) {
  647. if (closeCode == 1004 ||
  648. closeCode == 1005 ||
  649. closeCode == 1006) {
  650. return NO;
  651. }
  652. return YES;
  653. }
  654. if (closeCode >= 3000 && closeCode <= 3999) {
  655. return YES;
  656. }
  657. if (closeCode >= 4000 && closeCode <= 4999) {
  658. return YES;
  659. }
  660. return NO;
  661. }
  662. // Note from RFC:
  663. //
  664. // If there is a body, the first two
  665. // bytes of the body MUST be a 2-byte unsigned integer (in network byte
  666. // order) representing a status code with value /code/ defined in
  667. // Section 7.4. Following the 2-byte integer the body MAY contain UTF-8
  668. // encoded data with value /reason/, the interpretation of which is not
  669. // defined by this specification.
  670. - (void)handleCloseWithData:(NSData *)data;
  671. {
  672. size_t dataSize = data.length;
  673. __block uint16_t closeCode = 0;
  674. SRFastLog(@"Received close frame");
  675. if (dataSize == 1) {
  676. // TODO handle error
  677. [self _closeWithProtocolError:@"Payload for close must be larger than 2 bytes"];
  678. return;
  679. } else if (dataSize >= 2) {
  680. [data getBytes:&closeCode length:sizeof(closeCode)];
  681. _closeCode = EndianU16_BtoN(closeCode);
  682. if (!closeCodeIsValid(_closeCode)) {
  683. [self _closeWithProtocolError:[NSString stringWithFormat:@"Cannot have close code of %d", _closeCode]];
  684. return;
  685. }
  686. if (dataSize > 2) {
  687. _closeReason = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(2, dataSize - 2)] encoding:NSUTF8StringEncoding];
  688. if (!_closeReason) {
  689. [self _closeWithProtocolError:@"Close reason MUST be valid UTF-8"];
  690. return;
  691. }
  692. }
  693. } else {
  694. _closeCode = SRStatusNoStatusReceived;
  695. }
  696. [self assertOnWorkQueue];
  697. if (self.readyState == SR_OPEN) {
  698. [self closeWithCode:1000 reason:nil];
  699. }
  700. dispatch_async(_workQueue, ^{
  701. [self closeConnection];
  702. });
  703. }
  704. - (void)closeConnection;
  705. {
  706. [self assertOnWorkQueue];
  707. SRFastLog(@"Trying to disconnect");
  708. _closeWhenFinishedWriting = YES;
  709. [self _pumpWriting];
  710. }
  711. - (void)_handleFrameWithData:(NSData *)frameData opCode:(NSInteger)opcode;
  712. {
  713. // Check that the current data is valid UTF8
  714. BOOL isControlFrame = (opcode == SROpCodePing || opcode == SROpCodePong || opcode == SROpCodeConnectionClose);
  715. if (!isControlFrame) {
  716. [self _readFrameNew];
  717. } else {
  718. dispatch_async(_workQueue, ^{
  719. [self _readFrameContinue];
  720. });
  721. }
  722. //frameData will be copied before passing to handlers
  723. //otherwise there can be misbehaviours when value at the pointer is changed
  724. switch (opcode) {
  725. case SROpCodeTextFrame: {
  726. if ([self.delegate respondsToSelector:@selector(webSocketShouldConvertTextFrameToString:)] && ![self.delegate webSocketShouldConvertTextFrameToString:self]) {
  727. [self _handleMessage:[frameData copy]];
  728. } else {
  729. NSString *str = [[NSString alloc] initWithData:frameData encoding:NSUTF8StringEncoding];
  730. if (str == nil && frameData) {
  731. [self closeWithCode:SRStatusCodeInvalidUTF8 reason:@"Text frames must be valid UTF-8"];
  732. dispatch_async(_workQueue, ^{
  733. [self closeConnection];
  734. });
  735. return;
  736. }
  737. [self _handleMessage:str];
  738. }
  739. break;
  740. }
  741. case SROpCodeBinaryFrame:
  742. [self _handleMessage:[frameData copy]];
  743. break;
  744. case SROpCodeConnectionClose:
  745. [self handleCloseWithData:[frameData copy]];
  746. break;
  747. case SROpCodePing:
  748. [self handlePing:[frameData copy]];
  749. break;
  750. case SROpCodePong:
  751. [self handlePong:[frameData copy]];
  752. break;
  753. default:
  754. [self _closeWithProtocolError:[NSString stringWithFormat:@"Unknown opcode %ld", (long)opcode]];
  755. // TODO: Handle invalid opcode
  756. break;
  757. }
  758. }
  759. - (void)_handleFrameHeader:(frame_header)frame_header curData:(NSData *)curData;
  760. {
  761. assert(frame_header.opcode != 0);
  762. if (self.readyState == SR_CLOSED) {
  763. return;
  764. }
  765. BOOL isControlFrame = (frame_header.opcode == SROpCodePing || frame_header.opcode == SROpCodePong || frame_header.opcode == SROpCodeConnectionClose);
  766. if (isControlFrame && !frame_header.fin) {
  767. [self _closeWithProtocolError:@"Fragmented control frames not allowed"];
  768. return;
  769. }
  770. if (isControlFrame && frame_header.payload_length >= 126) {
  771. [self _closeWithProtocolError:@"Control frames cannot have payloads larger than 126 bytes"];
  772. return;
  773. }
  774. if (!isControlFrame) {
  775. _currentFrameOpcode = frame_header.opcode;
  776. _currentFrameCount += 1;
  777. }
  778. if (frame_header.payload_length == 0) {
  779. if (isControlFrame) {
  780. [self _handleFrameWithData:curData opCode:frame_header.opcode];
  781. } else {
  782. if (frame_header.fin) {
  783. [self _handleFrameWithData:_currentFrameData opCode:frame_header.opcode];
  784. } else {
  785. // TODO add assert that opcode is not a control;
  786. [self _readFrameContinue];
  787. }
  788. }
  789. } else {
  790. assert(frame_header.payload_length <= SIZE_T_MAX);
  791. [self _addConsumerWithDataLength:(size_t)frame_header.payload_length callback:^(SRWebSocket *self, NSData *newData) {
  792. if (isControlFrame) {
  793. [self _handleFrameWithData:newData opCode:frame_header.opcode];
  794. } else {
  795. if (frame_header.fin) {
  796. [self _handleFrameWithData:self->_currentFrameData opCode:frame_header.opcode];
  797. } else {
  798. // TODO add assert that opcode is not a control;
  799. [self _readFrameContinue];
  800. }
  801. }
  802. } readToCurrentFrame:!isControlFrame unmaskBytes:frame_header.masked];
  803. }
  804. }
  805. /* From RFC:
  806. 0 1 2 3
  807. 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  808. +-+-+-+-+-------+-+-------------+-------------------------------+
  809. |F|R|R|R| opcode|M| Payload len | Extended payload length |
  810. |I|S|S|S| (4) |A| (7) | (16/64) |
  811. |N|V|V|V| |S| | (if payload len==126/127) |
  812. | |1|2|3| |K| | |
  813. +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
  814. | Extended payload length continued, if payload len == 127 |
  815. + - - - - - - - - - - - - - - - +-------------------------------+
  816. | |Masking-key, if MASK set to 1 |
  817. +-------------------------------+-------------------------------+
  818. | Masking-key (continued) | Payload Data |
  819. +-------------------------------- - - - - - - - - - - - - - - - +
  820. : Payload Data continued ... :
  821. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
  822. | Payload Data continued ... |
  823. +---------------------------------------------------------------+
  824. */
  825. static const uint8_t SRFinMask = 0x80;
  826. static const uint8_t SROpCodeMask = 0x0F;
  827. static const uint8_t SRRsvMask = 0x70;
  828. static const uint8_t SRMaskMask = 0x80;
  829. static const uint8_t SRPayloadLenMask = 0x7F;
  830. - (void)_readFrameContinue;
  831. {
  832. assert((_currentFrameCount == 0 && _currentFrameOpcode == 0) || (_currentFrameCount > 0 && _currentFrameOpcode > 0));
  833. [self _addConsumerWithDataLength:2 callback:^(SRWebSocket *self, NSData *data) {
  834. __block frame_header header = {0};
  835. const uint8_t *headerBuffer = data.bytes;
  836. assert(data.length >= 2);
  837. if (headerBuffer[0] & SRRsvMask) {
  838. [self _closeWithProtocolError:@"Server used RSV bits"];
  839. return;
  840. }
  841. uint8_t receivedOpcode = (SROpCodeMask & headerBuffer[0]);
  842. BOOL isControlFrame = (receivedOpcode == SROpCodePing || receivedOpcode == SROpCodePong || receivedOpcode == SROpCodeConnectionClose);
  843. if (!isControlFrame && receivedOpcode != 0 && self->_currentFrameCount > 0) {
  844. [self _closeWithProtocolError:@"all data frames after the initial data frame must have opcode 0"];
  845. return;
  846. }
  847. if (receivedOpcode == 0 && self->_currentFrameCount == 0) {
  848. [self _closeWithProtocolError:@"cannot continue a message"];
  849. return;
  850. }
  851. header.opcode = receivedOpcode == 0 ? self->_currentFrameOpcode : receivedOpcode;
  852. header.fin = !!(SRFinMask & headerBuffer[0]);
  853. header.masked = !!(SRMaskMask & headerBuffer[1]);
  854. header.payload_length = SRPayloadLenMask & headerBuffer[1];
  855. headerBuffer = NULL;
  856. if (header.masked) {
  857. [self _closeWithProtocolError:@"Client must receive unmasked data"];
  858. }
  859. size_t extra_bytes_needed = header.masked ? sizeof(_currentReadMaskKey) : 0;
  860. if (header.payload_length == 126) {
  861. extra_bytes_needed += sizeof(uint16_t);
  862. } else if (header.payload_length == 127) {
  863. extra_bytes_needed += sizeof(uint64_t);
  864. }
  865. if (extra_bytes_needed == 0) {
  866. [self _handleFrameHeader:header curData:self->_currentFrameData];
  867. } else {
  868. [self _addConsumerWithDataLength:extra_bytes_needed callback:^(SRWebSocket *self, NSData *data) {
  869. size_t mapped_size = data.length;
  870. #pragma unused (mapped_size)
  871. const void *mapped_buffer = data.bytes;
  872. size_t offset = 0;
  873. if (header.payload_length == 126) {
  874. assert(mapped_size >= sizeof(uint16_t));
  875. uint16_t newLen = EndianU16_BtoN(*(uint16_t *)(mapped_buffer));
  876. header.payload_length = newLen;
  877. offset += sizeof(uint16_t);
  878. } else if (header.payload_length == 127) {
  879. assert(mapped_size >= sizeof(uint64_t));
  880. header.payload_length = EndianU64_BtoN(*(uint64_t *)(mapped_buffer));
  881. offset += sizeof(uint64_t);
  882. } else {
  883. assert(header.payload_length < 126 && header.payload_length >= 0);
  884. }
  885. if (header.masked) {
  886. assert(mapped_size >= sizeof(_currentReadMaskOffset) + offset);
  887. memcpy(self->_currentReadMaskKey, ((uint8_t *)mapped_buffer) + offset, sizeof(self->_currentReadMaskKey));
  888. }
  889. [self _handleFrameHeader:header curData:self->_currentFrameData];
  890. } readToCurrentFrame:NO unmaskBytes:NO];
  891. }
  892. } readToCurrentFrame:NO unmaskBytes:NO];
  893. }
  894. - (void)_readFrameNew;
  895. {
  896. dispatch_async(_workQueue, ^{
  897. [_currentFrameData setLength:0];
  898. _currentFrameOpcode = 0;
  899. _currentFrameCount = 0;
  900. _readOpCount = 0;
  901. _currentStringScanPosition = 0;
  902. [self _readFrameContinue];
  903. });
  904. }
  905. - (void)_pumpWriting;
  906. {
  907. [self assertOnWorkQueue];
  908. NSUInteger dataLength = _outputBuffer.length;
  909. if (dataLength - _outputBufferOffset > 0 && _outputStream.hasSpaceAvailable) {
  910. NSInteger bytesWritten = [_outputStream write:_outputBuffer.bytes + _outputBufferOffset maxLength:dataLength - _outputBufferOffset];
  911. if (bytesWritten == -1) {
  912. [self _failWithError:[NSError errorWithDomain:SRWebSocketErrorDomain code:2145 userInfo:[NSDictionary dictionaryWithObject:@"Error writing to stream" forKey:NSLocalizedDescriptionKey]]];
  913. return;
  914. }
  915. _outputBufferOffset += bytesWritten;
  916. if (_outputBufferOffset > 4096 && _outputBufferOffset > (_outputBuffer.length >> 1)) {
  917. _outputBuffer = [[NSMutableData alloc] initWithBytes:(char *)_outputBuffer.bytes + _outputBufferOffset length:_outputBuffer.length - _outputBufferOffset];
  918. _outputBufferOffset = 0;
  919. }
  920. }
  921. if (_closeWhenFinishedWriting &&
  922. _outputBuffer.length - _outputBufferOffset == 0 &&
  923. (_inputStream.streamStatus != NSStreamStatusNotOpen &&
  924. _inputStream.streamStatus != NSStreamStatusClosed) &&
  925. !_sentClose) {
  926. _sentClose = YES;
  927. @synchronized(self) {
  928. [_outputStream close];
  929. [_inputStream close];
  930. for (NSArray *runLoop in [_scheduledRunloops copy]) {
  931. [self unscheduleFromRunLoop:[runLoop objectAtIndex:0] forMode:[runLoop objectAtIndex:1]];
  932. }
  933. }
  934. if (!_failed) {
  935. [self _performDelegateBlock:^{
  936. if ([self.delegate respondsToSelector:@selector(webSocket:didCloseWithCode:reason:wasClean:)]) {
  937. [self.delegate webSocket:self didCloseWithCode:_closeCode reason:_closeReason wasClean:YES];
  938. }
  939. }];
  940. }
  941. [self _scheduleCleanup];
  942. }
  943. }
  944. - (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback;
  945. {
  946. [self assertOnWorkQueue];
  947. [self _addConsumerWithScanner:consumer callback:callback dataLength:0];
  948. }
  949. - (void)_addConsumerWithDataLength:(size_t)dataLength callback:(data_callback)callback readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes;
  950. {
  951. [self assertOnWorkQueue];
  952. assert(dataLength);
  953. [_consumers addObject:[_consumerPool consumerWithScanner:nil handler:callback bytesNeeded:dataLength readToCurrentFrame:readToCurrentFrame unmaskBytes:unmaskBytes]];
  954. [self _pumpScanner];
  955. }
  956. - (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback dataLength:(size_t)dataLength;
  957. {
  958. [self assertOnWorkQueue];
  959. [_consumers addObject:[_consumerPool consumerWithScanner:consumer handler:callback bytesNeeded:dataLength readToCurrentFrame:NO unmaskBytes:NO]];
  960. [self _pumpScanner];
  961. }
  962. - (void)_scheduleCleanup
  963. {
  964. @synchronized(self) {
  965. if (_cleanupScheduled) {
  966. return;
  967. }
  968. _cleanupScheduled = YES;
  969. // Cleanup NSStream delegate's in the same RunLoop used by the streams themselves:
  970. // This way we'll prevent race conditions between handleEvent and SRWebsocket's dealloc
  971. NSTimer *timer = [NSTimer timerWithTimeInterval:(0.0f) target:self selector:@selector(_cleanupSelfReference:) userInfo:nil repeats:NO];
  972. [[NSRunLoop SR_networkRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
  973. }
  974. }
  975. - (void)_cleanupSelfReference:(NSTimer *)timer
  976. {
  977. @synchronized(self) {
  978. // Nuke NSStream delegate's
  979. _inputStream.delegate = nil;
  980. _outputStream.delegate = nil;
  981. // Remove the streams, right now, from the networkRunLoop
  982. [_inputStream close];
  983. [_outputStream close];
  984. }
  985. // Cleanup selfRetain in the same GCD queue as usual
  986. dispatch_async(_workQueue, ^{
  987. _selfRetain = nil;
  988. });
  989. }
  990. static const char CRLFCRLFBytes[] = {'\r', '\n', '\r', '\n'};
  991. - (void)_readUntilHeaderCompleteWithCallback:(data_callback)dataHandler;
  992. {
  993. [self _readUntilBytes:CRLFCRLFBytes length:sizeof(CRLFCRLFBytes) callback:dataHandler];
  994. }
  995. - (void)_readUntilBytes:(const void *)bytes length:(size_t)length callback:(data_callback)dataHandler;
  996. {
  997. // TODO optimize so this can continue from where we last searched
  998. stream_scanner consumer = ^size_t(NSData *data) {
  999. __block size_t found_size = 0;
  1000. __block size_t match_count = 0;
  1001. size_t size = data.length;
  1002. const unsigned char *buffer = data.bytes;
  1003. for (size_t i = 0; i < size; i++ ) {
  1004. if (((const unsigned char *)buffer)[i] == ((const unsigned char *)bytes)[match_count]) {
  1005. match_count += 1;
  1006. if (match_count == length) {
  1007. found_size = i + 1;
  1008. break;
  1009. }
  1010. } else {
  1011. match_count = 0;
  1012. }
  1013. }
  1014. return found_size;
  1015. };
  1016. [self _addConsumerWithScanner:consumer callback:dataHandler];
  1017. }
  1018. // Returns true if did work
  1019. - (BOOL)_innerPumpScanner {
  1020. BOOL didWork = NO;
  1021. if (self.readyState >= SR_CLOSED) {
  1022. return didWork;
  1023. }
  1024. if (!_consumers.count) {
  1025. return didWork;
  1026. }
  1027. size_t curSize = _readBuffer.length - _readBufferOffset;
  1028. if (!curSize) {
  1029. return didWork;
  1030. }
  1031. SRIOConsumer *consumer = [_consumers objectAtIndex:0];
  1032. size_t bytesNeeded = consumer.bytesNeeded;
  1033. size_t foundSize = 0;
  1034. if (consumer.consumer) {
  1035. NSData *tempView = [NSData dataWithBytesNoCopy:(char *)_readBuffer.bytes + _readBufferOffset length:_readBuffer.length - _readBufferOffset freeWhenDone:NO];
  1036. foundSize = consumer.consumer(tempView);
  1037. } else {
  1038. assert(consumer.bytesNeeded);
  1039. if (curSize >= bytesNeeded) {
  1040. foundSize = bytesNeeded;
  1041. } else if (consumer.readToCurrentFrame) {
  1042. foundSize = curSize;
  1043. }
  1044. }
  1045. NSData *slice = nil;
  1046. if (consumer.readToCurrentFrame || foundSize) {
  1047. NSRange sliceRange = NSMakeRange(_readBufferOffset, foundSize);
  1048. slice = [_readBuffer subdataWithRange:sliceRange];
  1049. _readBufferOffset += foundSize;
  1050. if (_readBufferOffset > 4096 && _readBufferOffset > (_readBuffer.length >> 1)) {
  1051. _readBuffer = [[NSMutableData alloc] initWithBytes:(char *)_readBuffer.bytes + _readBufferOffset length:_readBuffer.length - _readBufferOffset]; _readBufferOffset = 0;
  1052. }
  1053. if (consumer.unmaskBytes) {
  1054. NSMutableData *mutableSlice = [slice mutableCopy];
  1055. NSUInteger len = mutableSlice.length;
  1056. uint8_t *bytes = mutableSlice.mutableBytes;
  1057. for (NSUInteger i = 0; i < len; i++) {
  1058. bytes[i] = bytes[i] ^ _currentReadMaskKey[_currentReadMaskOffset % sizeof(_currentReadMaskKey)];
  1059. _currentReadMaskOffset += 1;
  1060. }
  1061. slice = mutableSlice;
  1062. }
  1063. if (consumer.readToCurrentFrame) {
  1064. [_currentFrameData appendData:slice];
  1065. _readOpCount += 1;
  1066. if (_currentFrameOpcode == SROpCodeTextFrame) {
  1067. // Validate UTF8 stuff.
  1068. size_t currentDataSize = _currentFrameData.length;
  1069. if (_currentFrameOpcode == SROpCodeTextFrame && currentDataSize > 0) {
  1070. // TODO: Optimize the crap out of this. Don't really have to copy all the data each time
  1071. size_t scanSize = currentDataSize - _currentStringScanPosition;
  1072. NSData *scan_data = [_currentFrameData subdataWithRange:NSMakeRange(_currentStringScanPosition, scanSize)];
  1073. int32_t valid_utf8_size = validate_dispatch_data_partial_string(scan_data);
  1074. if (valid_utf8_size == -1) {
  1075. [self closeWithCode:SRStatusCodeInvalidUTF8 reason:@"Text frames must be valid UTF-8"];
  1076. dispatch_async(_workQueue, ^{
  1077. [self closeConnection];
  1078. });
  1079. return didWork;
  1080. } else {
  1081. _currentStringScanPosition += valid_utf8_size;
  1082. }
  1083. }
  1084. }
  1085. consumer.bytesNeeded -= foundSize;
  1086. if (consumer.bytesNeeded == 0) {
  1087. [_consumers removeObjectAtIndex:0];
  1088. consumer.handler(self, nil);
  1089. [_consumerPool returnConsumer:consumer];
  1090. didWork = YES;
  1091. }
  1092. } else if (foundSize) {
  1093. [_consumers removeObjectAtIndex:0];
  1094. consumer.handler(self, slice);
  1095. [_consumerPool returnConsumer:consumer];
  1096. didWork = YES;
  1097. }
  1098. }
  1099. return didWork;
  1100. }
  1101. -(void)_pumpScanner;
  1102. {
  1103. [self assertOnWorkQueue];
  1104. if (!_isPumping) {
  1105. _isPumping = YES;
  1106. } else {
  1107. return;
  1108. }
  1109. while ([self _innerPumpScanner]) {
  1110. }
  1111. _isPumping = NO;
  1112. }
  1113. //#define NOMASK
  1114. static const size_t SRFrameHeaderOverhead = 32;
  1115. - (void)_sendFrameWithOpcode:(SROpCode)opcode data:(id)data;
  1116. {
  1117. [self assertOnWorkQueue];
  1118. if (nil == data) {
  1119. return;
  1120. }
  1121. NSAssert([data isKindOfClass:[NSData class]] || [data isKindOfClass:[NSString class]], @"NSString or NSData");
  1122. size_t payloadLength = [data isKindOfClass:[NSString class]] ? [(NSString *)data lengthOfBytesUsingEncoding:NSUTF8StringEncoding] : [data length];
  1123. NSMutableData *frame = [[NSMutableData alloc] initWithLength:payloadLength + SRFrameHeaderOverhead];
  1124. if (!frame) {
  1125. [self closeWithCode:SRStatusCodeMessageTooBig reason:@"Message too big"];
  1126. return;
  1127. }
  1128. uint8_t *frame_buffer = (uint8_t *)[frame mutableBytes];
  1129. // set fin
  1130. frame_buffer[0] = SRFinMask | opcode;
  1131. BOOL useMask = YES;
  1132. #ifdef NOMASK
  1133. useMask = NO;
  1134. #endif
  1135. if (useMask) {
  1136. // set the mask and header
  1137. frame_buffer[1] |= SRMaskMask;
  1138. }
  1139. size_t frame_buffer_size = 2;
  1140. const uint8_t *unmasked_payload = NULL;
  1141. if ([data isKindOfClass:[NSData class]]) {
  1142. unmasked_payload = (uint8_t *)[data bytes];
  1143. } else if ([data isKindOfClass:[NSString class]]) {
  1144. unmasked_payload = (const uint8_t *)[data UTF8String];
  1145. } else {
  1146. return;
  1147. }
  1148. if (payloadLength < 126) {
  1149. frame_buffer[1] |= payloadLength;
  1150. } else if (payloadLength <= UINT16_MAX) {
  1151. frame_buffer[1] |= 126;
  1152. *((uint16_t *)(frame_buffer + frame_buffer_size)) = EndianU16_BtoN((uint16_t)payloadLength);
  1153. frame_buffer_size += sizeof(uint16_t);
  1154. } else {
  1155. frame_buffer[1] |= 127;
  1156. *((uint64_t *)(frame_buffer + frame_buffer_size)) = EndianU64_BtoN((uint64_t)payloadLength);
  1157. frame_buffer_size += sizeof(uint64_t);
  1158. }
  1159. if (!useMask) {
  1160. for (size_t i = 0; i < payloadLength; i++) {
  1161. frame_buffer[frame_buffer_size] = unmasked_payload[i];
  1162. frame_buffer_size += 1;
  1163. }
  1164. } else {
  1165. uint8_t *mask_key = frame_buffer + frame_buffer_size;
  1166. SecRandomCopyBytes(kSecRandomDefault, sizeof(uint32_t), (uint8_t *)mask_key);
  1167. frame_buffer_size += sizeof(uint32_t);
  1168. // TODO: could probably optimize this with SIMD
  1169. for (size_t i = 0; i < payloadLength; i++) {
  1170. frame_buffer[frame_buffer_size] = unmasked_payload[i] ^ mask_key[i % sizeof(uint32_t)];
  1171. frame_buffer_size += 1;
  1172. }
  1173. }
  1174. assert(frame_buffer_size <= [frame length]);
  1175. frame.length = frame_buffer_size;
  1176. [self _writeData:frame];
  1177. }
  1178. - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode;
  1179. {
  1180. __weak typeof(self) weakSelf = self;
  1181. if (_secure && !_pinnedCertFound && (eventCode == NSStreamEventHasBytesAvailable || eventCode == NSStreamEventHasSpaceAvailable)) {
  1182. NSArray *sslCerts = [_urlRequest SR_SSLPinnedCertificates];
  1183. if (sslCerts) {
  1184. SecTrustRef secTrust = (__bridge SecTrustRef)[aStream propertyForKey:(__bridge id)kCFStreamPropertySSLPeerTrust];
  1185. if (secTrust) {
  1186. NSInteger numCerts = SecTrustGetCertificateCount(secTrust);
  1187. for (NSInteger i = 0; i < numCerts && !_pinnedCertFound; i++) {
  1188. SecCertificateRef cert = SecTrustGetCertificateAtIndex(secTrust, i);
  1189. NSData *certData = CFBridgingRelease(SecCertificateCopyData(cert));
  1190. for (id ref in sslCerts) {
  1191. SecCertificateRef trustedCert = (__bridge SecCertificateRef)ref;
  1192. NSData *trustedCertData = CFBridgingRelease(SecCertificateCopyData(trustedCert));
  1193. if ([trustedCertData isEqualToData:certData]) {
  1194. _pinnedCertFound = YES;
  1195. break;
  1196. }
  1197. }
  1198. }
  1199. }
  1200. if (!_pinnedCertFound) {
  1201. dispatch_async(_workQueue, ^{
  1202. NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : @"Invalid server cert" };
  1203. [weakSelf _failWithError:[NSError errorWithDomain:@"org.lolrus.SocketRocket" code:23556 userInfo:userInfo]];
  1204. });
  1205. return;
  1206. } else if (aStream == _outputStream) {
  1207. dispatch_async(_workQueue, ^{
  1208. [self didConnect];
  1209. });
  1210. }
  1211. }
  1212. }
  1213. dispatch_async(_workQueue, ^{
  1214. [weakSelf safeHandleEvent:eventCode stream:aStream];
  1215. });
  1216. }
  1217. - (void)safeHandleEvent:(NSStreamEvent)eventCode stream:(NSStream *)aStream
  1218. {
  1219. switch (eventCode) {
  1220. case NSStreamEventOpenCompleted: {
  1221. SRFastLog(@"NSStreamEventOpenCompleted %@", aStream);
  1222. if (self.readyState >= SR_CLOSING) {
  1223. return;
  1224. }
  1225. assert(_readBuffer);
  1226. // didConnect fires after certificate verification if we're using pinned certificates.
  1227. BOOL usingPinnedCerts = [[_urlRequest SR_SSLPinnedCertificates] count] > 0;
  1228. if ((!_secure || !usingPinnedCerts) && self.readyState == SR_CONNECTING && aStream == _inputStream) {
  1229. [self didConnect];
  1230. }
  1231. [self _pumpWriting];
  1232. [self _pumpScanner];
  1233. break;
  1234. }
  1235. case NSStreamEventErrorOccurred: {
  1236. SRFastLog(@"NSStreamEventErrorOccurred %@ %@", aStream, [[aStream streamError] copy]);
  1237. /// TODO specify error better!
  1238. [self _failWithError:aStream.streamError];
  1239. _readBufferOffset = 0;
  1240. [_readBuffer setLength:0];
  1241. break;
  1242. }
  1243. case NSStreamEventEndEncountered: {
  1244. [self _pumpScanner];
  1245. SRFastLog(@"NSStreamEventEndEncountered %@", aStream);
  1246. if (aStream.streamError) {
  1247. [self _failWithError:aStream.streamError];
  1248. } else {
  1249. dispatch_async(_workQueue, ^{
  1250. if (self.readyState != SR_CLOSED) {
  1251. self.readyState = SR_CLOSED;
  1252. [self _scheduleCleanup];
  1253. }
  1254. if (!_sentClose && !_failed) {
  1255. _sentClose = YES;
  1256. // If we get closed in this state it's probably not clean because we should be sending this when we send messages
  1257. [self _performDelegateBlock:^{
  1258. if ([self.delegate respondsToSelector:@selector(webSocket:didCloseWithCode:reason:wasClean:)]) {
  1259. [self.delegate webSocket:self didCloseWithCode:SRStatusCodeGoingAway reason:@"Stream end encountered" wasClean:NO];
  1260. }
  1261. }];
  1262. }
  1263. });
  1264. }
  1265. break;
  1266. }
  1267. case NSStreamEventHasBytesAvailable: {
  1268. SRFastLog(@"NSStreamEventHasBytesAvailable %@", aStream);
  1269. const int bufferSize = 2048;
  1270. uint8_t buffer[bufferSize];
  1271. while (_inputStream.hasBytesAvailable) {
  1272. NSInteger bytes_read = [_inputStream read:buffer maxLength:bufferSize];
  1273. if (bytes_read > 0) {
  1274. [_readBuffer appendBytes:buffer length:bytes_read];
  1275. } else if (bytes_read < 0) {
  1276. [self _failWithError:_inputStream.streamError];
  1277. }
  1278. if (bytes_read != bufferSize) {
  1279. break;
  1280. }
  1281. };
  1282. [self _pumpScanner];
  1283. break;
  1284. }
  1285. case NSStreamEventHasSpaceAvailable: {
  1286. SRFastLog(@"NSStreamEventHasSpaceAvailable %@", aStream);
  1287. [self _pumpWriting];
  1288. break;
  1289. }
  1290. default:
  1291. SRFastLog(@"(default) %@", aStream);
  1292. break;
  1293. }
  1294. }
  1295. @end
  1296. @implementation SRIOConsumer
  1297. @synthesize bytesNeeded = _bytesNeeded;
  1298. @synthesize consumer = _scanner;
  1299. @synthesize handler = _handler;
  1300. @synthesize readToCurrentFrame = _readToCurrentFrame;
  1301. @synthesize unmaskBytes = _unmaskBytes;
  1302. - (void)setupWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes;
  1303. {
  1304. _scanner = [scanner copy];
  1305. _handler = [handler copy];
  1306. _bytesNeeded = bytesNeeded;
  1307. _readToCurrentFrame = readToCurrentFrame;
  1308. _unmaskBytes = unmaskBytes;
  1309. assert(_scanner || _bytesNeeded);
  1310. }
  1311. @end
  1312. @implementation SRIOConsumerPool {
  1313. NSUInteger _poolSize;
  1314. NSMutableArray *_bufferedConsumers;
  1315. }
  1316. - (id)initWithBufferCapacity:(NSUInteger)poolSize;
  1317. {
  1318. self = [super init];
  1319. if (self) {
  1320. _poolSize = poolSize;
  1321. _bufferedConsumers = [[NSMutableArray alloc] initWithCapacity:poolSize];
  1322. }
  1323. return self;
  1324. }
  1325. - (id)init
  1326. {
  1327. return [self initWithBufferCapacity:8];
  1328. }
  1329. - (SRIOConsumer *)consumerWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes;
  1330. {
  1331. SRIOConsumer *consumer = nil;
  1332. if (_bufferedConsumers.count) {
  1333. consumer = [_bufferedConsumers lastObject];
  1334. [_bufferedConsumers removeLastObject];
  1335. } else {
  1336. consumer = [[SRIOConsumer alloc] init];
  1337. }
  1338. [consumer setupWithScanner:scanner handler:handler bytesNeeded:bytesNeeded readToCurrentFrame:readToCurrentFrame unmaskBytes:unmaskBytes];
  1339. return consumer;
  1340. }
  1341. - (void)returnConsumer:(SRIOConsumer *)consumer;
  1342. {
  1343. if (_bufferedConsumers.count < _poolSize) {
  1344. [_bufferedConsumers addObject:consumer];
  1345. }
  1346. }
  1347. @end
  1348. @implementation NSURLRequest (SRCertificateAdditions)
  1349. - (NSArray *)SR_SSLPinnedCertificates;
  1350. {
  1351. return [NSURLProtocol propertyForKey:@"SR_SSLPinnedCertificates" inRequest:self];
  1352. }
  1353. @end
  1354. @implementation NSMutableURLRequest (SRCertificateAdditions)
  1355. - (NSArray *)SR_SSLPinnedCertificates;
  1356. {
  1357. return [NSURLProtocol propertyForKey:@"SR_SSLPinnedCertificates" inRequest:self];
  1358. }
  1359. - (void)setSR_SSLPinnedCertificates:(NSArray *)SR_SSLPinnedCertificates;
  1360. {
  1361. [NSURLProtocol setProperty:SR_SSLPinnedCertificates forKey:@"SR_SSLPinnedCertificates" inRequest:self];
  1362. }
  1363. @end
  1364. @implementation NSURL (SRWebSocket)
  1365. - (NSString *)SR_origin;
  1366. {
  1367. NSString *scheme = [self.scheme lowercaseString];
  1368. if ([scheme isEqualToString:@"wss"]) {
  1369. scheme = @"https";
  1370. } else if ([scheme isEqualToString:@"ws"]) {
  1371. scheme = @"http";
  1372. }
  1373. BOOL portIsDefault = !self.port ||
  1374. ([scheme isEqualToString:@"http"] && self.port.integerValue == 80) ||
  1375. ([scheme isEqualToString:@"https"] && self.port.integerValue == 443);
  1376. if (!portIsDefault) {
  1377. return [NSString stringWithFormat:@"%@://%@:%@", scheme, self.host, self.port];
  1378. } else {
  1379. return [NSString stringWithFormat:@"%@://%@", scheme, self.host];
  1380. }
  1381. }
  1382. @end
  1383. //#define SR_ENABLE_LOG
  1384. static inline void SRFastLog(NSString *format, ...) {
  1385. #ifdef SR_ENABLE_LOG
  1386. __block va_list arg_list;
  1387. va_start (arg_list, format);
  1388. NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list];
  1389. va_end(arg_list);
  1390. HLog(@"[SR] %@", formattedString);
  1391. #endif
  1392. }
  1393. #ifdef HAS_ICU
  1394. static inline int32_t validate_dispatch_data_partial_string(NSData *data) {
  1395. if ([data length] > INT32_MAX) {
  1396. // INT32_MAX is the limit so long as this Framework is using 32 bit ints everywhere.
  1397. return -1;
  1398. }
  1399. int32_t size = (int32_t)[data length];
  1400. const void * contents = [data bytes];
  1401. const uint8_t *str = (const uint8_t *)contents;
  1402. UChar32 codepoint = 1;
  1403. int32_t offset = 0;
  1404. int32_t lastOffset = 0;
  1405. while(offset < size && codepoint > 0) {
  1406. lastOffset = offset;
  1407. U8_NEXT(str, offset, size, codepoint);
  1408. }
  1409. if (codepoint == -1) {
  1410. // Check to see if the last byte is valid or whether it was just continuing
  1411. if (!U8_IS_LEAD(str[lastOffset]) || U8_COUNT_TRAIL_BYTES(str[lastOffset]) + lastOffset < (int32_t)size) {
  1412. size = -1;
  1413. } else {
  1414. uint8_t leadByte = str[lastOffset];
  1415. U8_MASK_LEAD_BYTE(leadByte, U8_COUNT_TRAIL_BYTES(leadByte));
  1416. for (int i = lastOffset + 1; i < offset; i++) {
  1417. if (U8_IS_SINGLE(str[i]) || U8_IS_LEAD(str[i]) || !U8_IS_TRAIL(str[i])) {
  1418. size = -1;
  1419. }
  1420. }
  1421. if (size != -1) {
  1422. size = lastOffset;
  1423. }
  1424. }
  1425. }
  1426. if (size != -1 && ![[NSString alloc] initWithBytesNoCopy:(char *)[data bytes] length:size encoding:NSUTF8StringEncoding freeWhenDone:NO]) {
  1427. size = -1;
  1428. }
  1429. return size;
  1430. }
  1431. #else
  1432. // This is a hack, and probably not optimal
  1433. static inline int32_t validate_dispatch_data_partial_string(NSData *data) {
  1434. static const int maxCodepointSize = 3;
  1435. for (int i = 0; i < maxCodepointSize; i++) {
  1436. NSString *str = [[NSString alloc] initWithBytesNoCopy:(char *)data.bytes length:data.length - i encoding:NSUTF8StringEncoding freeWhenDone:NO];
  1437. if (str) {
  1438. return (int32_t)data.length - i;
  1439. }
  1440. }
  1441. return -1;
  1442. }
  1443. #endif
  1444. static _SRRunLoopThread *networkThread = nil;
  1445. static NSRunLoop *networkRunLoop = nil;
  1446. @implementation NSRunLoop (SRWebSocket)
  1447. + (NSRunLoop *)SR_networkRunLoop {
  1448. static dispatch_once_t onceToken;
  1449. dispatch_once(&onceToken, ^{
  1450. networkThread = [[_SRRunLoopThread alloc] init];
  1451. networkThread.name = @"com.squareup.SocketRocket.NetworkThread";
  1452. [networkThread start];
  1453. networkRunLoop = networkThread.runLoop;
  1454. });
  1455. return networkRunLoop;
  1456. }
  1457. @end
  1458. @implementation _SRRunLoopThread {
  1459. dispatch_group_t _waitGroup;
  1460. }
  1461. @synthesize runLoop = _runLoop;
  1462. - (void)dealloc
  1463. {
  1464. sr_dispatch_release(_waitGroup);
  1465. }
  1466. - (id)init
  1467. {
  1468. self = [super init];
  1469. if (self) {
  1470. _waitGroup = dispatch_group_create();
  1471. dispatch_group_enter(_waitGroup);
  1472. }
  1473. return self;
  1474. }
  1475. - (void)main;
  1476. {
  1477. @autoreleasepool {
  1478. _runLoop = [NSRunLoop currentRunLoop];
  1479. dispatch_group_leave(_waitGroup);
  1480. // Add an empty run loop source to prevent runloop from spinning.
  1481. CFRunLoopSourceContext sourceCtx = {
  1482. .version = 0,
  1483. .info = NULL,
  1484. .retain = NULL,
  1485. .release = NULL,
  1486. .copyDescription = NULL,
  1487. .equal = NULL,
  1488. .hash = NULL,
  1489. .schedule = NULL,
  1490. .cancel = NULL,
  1491. .perform = NULL
  1492. };
  1493. CFRunLoopSourceRef source = CFRunLoopSourceCreate(NULL, 0, &sourceCtx);
  1494. CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
  1495. CFRelease(source);
  1496. while ([_runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) {
  1497. }
  1498. assert(NO);
  1499. }
  1500. }
  1501. - (NSRunLoop *)runLoop;
  1502. {
  1503. dispatch_group_wait(_waitGroup, DISPATCH_TIME_FOREVER);
  1504. return _runLoop;
  1505. }
  1506. @end