Skip to content

Commit 47f87cc

Browse files
committed
Merging latest changes from CocoaHTTPServer project.
1 parent d982c56 commit 47f87cc

File tree

2 files changed

+213
-6
lines changed

2 files changed

+213
-6
lines changed

Xcode/WebServerIPhone/Vendor/CocoaHTTPServer/HTTPServer.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ - (void)dealloc
108108
dispatch_release(connectionQueue);
109109

110110
[asyncSocket setDelegate:nil delegateQueue:NULL];
111+
112+
113+
114+
111115
}
112116

113117
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Xcode/WebServerIPhone/Vendor/CocoaHTTPServer/WebSocket.m

Lines changed: 209 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,34 @@
2222

2323
#define TAG_PREFIX 300
2424
#define TAG_MSG_PLUS_SUFFIX 301
25+
#define TAG_MSG_WITH_LENGTH 302
26+
#define TAG_MSG_MASKING_KEY 303
27+
#define TAG_PAYLOAD_PREFIX 304
28+
#define TAG_PAYLOAD_LENGTH 305
29+
#define TAG_PAYLOAD_LENGTH16 306
30+
#define TAG_PAYLOAD_LENGTH64 307
31+
32+
#define WS_OP_CONTINUATION_FRAME 0
33+
#define WS_OP_TEXT_FRAME 1
34+
#define WS_OP_BINARY_FRAME 2
35+
#define WS_OP_CONNECTION_CLOSE 8
36+
#define WS_OP_PING 9
37+
#define WS_OP_PONG 10
38+
39+
static inline BOOL WS_OP_IS_FINAL_FRAGMENT(UInt8 frame)
40+
{
41+
return (frame & 0x80) ? YES : NO;
42+
}
43+
44+
static inline BOOL WS_PAYLOAD_IS_MASKED(UInt8 frame)
45+
{
46+
return (frame & 0x80) ? YES : NO;
47+
}
2548

49+
static inline NSUInteger WS_PAYLOAD_LENGTH(UInt8 frame)
50+
{
51+
return frame & 0x7F;
52+
}
2653

2754
@interface WebSocket (PrivateAPI)
2855

@@ -37,6 +64,12 @@ - (void)sendResponseHeaders;
3764
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3865

3966
@implementation WebSocket
67+
{
68+
BOOL isRFC6455;
69+
BOOL nextFrameMasked;
70+
NSUInteger nextOpCode;
71+
NSData *maskingKey;
72+
}
4073

4174
+ (BOOL)isWebSocketRequest:(HTTPMessage *)request
4275
{
@@ -106,6 +139,16 @@ + (BOOL)isVersion76Request:(HTTPMessage *)request
106139
return isVersion76;
107140
}
108141

142+
+ (BOOL)isRFC6455Request:(HTTPMessage *)request
143+
{
144+
NSString *key = [request headerField:@"Sec-WebSocket-Key"];
145+
BOOL isRFC6455 = (key != nil);
146+
147+
HTTPLogTrace2(@"%@: %@ - %@", THIS_FILE, THIS_METHOD, (isRFC6455 ? @"YES" : @"NO"));
148+
149+
return isRFC6455;
150+
}
151+
109152
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
110153
#pragma mark Setup and Teardown
111154
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -139,6 +182,7 @@ - (id)initWithRequest:(HTTPMessage *)aRequest socket:(GCDAsyncSocket *)socket
139182

140183
isOpen = NO;
141184
isVersion76 = [[self class] isVersion76Request:request];
185+
isRFC6455 = [[self class] isRFC6455Request:request];
142186

143187
term = [[NSData alloc] initWithBytes:"\xFF" length:1];
144188
}
@@ -276,6 +320,12 @@ - (NSString *)locationResponseHeaderValue
276320
return location;
277321
}
278322

323+
- (NSString *)secWebSocketKeyResponseHeaderValue {
324+
NSString *key = [request headerField: @"Sec-WebSocket-Key"];
325+
NSString *guid = @"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
326+
return [[key stringByAppendingString: guid] dataUsingEncoding: NSUTF8StringEncoding].sha1Digest.base64Encoded;
327+
}
328+
279329
- (void)sendResponseHeaders
280330
{
281331
HTTPLogTrace();
@@ -351,6 +401,11 @@ - (void)sendResponseHeaders
351401
[wsResponse setHeaderField:originField value:originValue];
352402
[wsResponse setHeaderField:locationField value:locationValue];
353403

404+
NSString *acceptValue = [self secWebSocketKeyResponseHeaderValue];
405+
if (acceptValue) {
406+
[wsResponse setHeaderField: @"Sec-WebSocket-Accept" value: acceptValue];
407+
}
408+
354409
NSData *responseHeaders = [wsResponse messageData];
355410

356411

@@ -469,7 +524,7 @@ - (void)didOpen
469524
// Don't forget to invoke [super didOpen] in your method.
470525

471526
// Start reading for messages
472-
[asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PREFIX];
527+
[asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:(isRFC6455 ? TAG_PAYLOAD_PREFIX : TAG_PREFIX)];
473528

474529
// Notify delegate
475530
if ([delegate respondsToSelector:@selector(webSocketDidOpen:)])
@@ -483,12 +538,43 @@ - (void)sendMessage:(NSString *)msg
483538
HTTPLogTrace();
484539

485540
NSData *msgData = [msg dataUsingEncoding:NSUTF8StringEncoding];
541+
NSMutableData *data = nil;
486542

487-
NSMutableData *data = [NSMutableData dataWithCapacity:([msgData length] + 2)];
488-
489-
[data appendBytes:"\x00" length:1];
490-
[data appendData:msgData];
491-
[data appendBytes:"\xFF" length:1];
543+
if (isRFC6455)
544+
{
545+
NSUInteger length = msgData.length;
546+
if (length <= 125)
547+
{
548+
data = [NSMutableData dataWithCapacity:(length + 2)];
549+
[data appendBytes: "\x81" length:1];
550+
UInt8 len = (UInt8)length;
551+
[data appendBytes: &len length:1];
552+
[data appendData:msgData];
553+
}
554+
else if (length <= 0xFFFF)
555+
{
556+
data = [NSMutableData dataWithCapacity:(length + 4)];
557+
[data appendBytes: "\x81\x7E" length:2];
558+
UInt16 len = (UInt16)length;
559+
[data appendBytes: (UInt8[]){len >> 8, len & 0xFF} length:2];
560+
[data appendData:msgData];
561+
}
562+
else
563+
{
564+
data = [NSMutableData dataWithCapacity:(length + 10)];
565+
[data appendBytes: "\x81\x7F" length:2];
566+
[data appendBytes: (UInt8[]){0, 0, 0, 0, (UInt8)(length >> 24), (UInt8)(length >> 16), (UInt8)(length >> 8), length & 0xFF} length:8];
567+
[data appendData:msgData];
568+
}
569+
}
570+
else
571+
{
572+
data = [NSMutableData dataWithCapacity:([msgData length] + 2)];
573+
574+
[data appendBytes:"\x00" length:1];
575+
[data appendData:msgData];
576+
[data appendBytes:"\xFF" length:1];
577+
}
492578

493579
// Remember: GCDAsyncSocket is thread-safe
494580

@@ -530,10 +616,42 @@ - (void)didClose
530616
[[NSNotificationCenter defaultCenter] postNotificationName:WebSocketDidDieNotification object:self];
531617
}
532618

619+
#pragma mark WebSocket Frame
620+
621+
- (BOOL)isValidWebSocketFrame:(UInt8)frame
622+
{
623+
NSUInteger rsv = frame & 0x70;
624+
NSUInteger opcode = frame & 0x0F;
625+
if (rsv || (3 <= opcode && opcode <= 7) || (0xB <= opcode && opcode <= 0xF))
626+
{
627+
return NO;
628+
}
629+
return YES;
630+
}
631+
533632
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
534633
#pragma mark AsyncSocket Delegate
535634
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
536635

636+
// 0 1 2 3
637+
// 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
638+
// +-+-+-+-+-------+-+-------------+-------------------------------+
639+
// |F|R|R|R| opcode|M| Payload len | Extended payload length |
640+
// |I|S|S|S| (4) |A| (7) | (16/64) |
641+
// |N|V|V|V| |S| | (if payload len==126/127) |
642+
// | |1|2|3| |K| | |
643+
// +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
644+
// | Extended payload length continued, if payload len == 127 |
645+
// + - - - - - - - - - - - - - - - +-------------------------------+
646+
// | |Masking-key, if MASK set to 1 |
647+
// +-------------------------------+-------------------------------+
648+
// | Masking-key (continued) | Payload Data |
649+
// +-------------------------------- - - - - - - - - - - - - - - - +
650+
// : Payload Data continued ... :
651+
// + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
652+
// | Payload Data continued ... |
653+
// +---------------------------------------------------------------+
654+
537655
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
538656
{
539657
HTTPLogTrace();
@@ -559,6 +677,91 @@ - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)t
559677
[self didClose];
560678
}
561679
}
680+
else if (tag == TAG_PAYLOAD_PREFIX)
681+
{
682+
UInt8 *pFrame = (UInt8 *)[data bytes];
683+
UInt8 frame = *pFrame;
684+
685+
if ([self isValidWebSocketFrame: frame])
686+
{
687+
nextOpCode = (frame & 0x0F);
688+
[asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH];
689+
}
690+
else
691+
{
692+
// Unsupported frame type
693+
[self didClose];
694+
}
695+
}
696+
else if (tag == TAG_PAYLOAD_LENGTH)
697+
{
698+
UInt8 frame = *(UInt8 *)[data bytes];
699+
BOOL masked = WS_PAYLOAD_IS_MASKED(frame);
700+
NSUInteger length = WS_PAYLOAD_LENGTH(frame);
701+
nextFrameMasked = masked;
702+
maskingKey = nil;
703+
if (length <= 125)
704+
{
705+
if (nextFrameMasked)
706+
{
707+
[asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY];
708+
}
709+
[asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_MSG_WITH_LENGTH];
710+
}
711+
else if (length == 126)
712+
{
713+
[asyncSocket readDataToLength:2 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH16];
714+
}
715+
else
716+
{
717+
[asyncSocket readDataToLength:8 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH64];
718+
}
719+
}
720+
else if (tag == TAG_PAYLOAD_LENGTH16)
721+
{
722+
UInt8 *pFrame = (UInt8 *)[data bytes];
723+
NSUInteger length = ((NSUInteger)pFrame[0] << 8) | (NSUInteger)pFrame[1];
724+
if (nextFrameMasked) {
725+
[asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY];
726+
}
727+
[asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_MSG_WITH_LENGTH];
728+
}
729+
else if (tag == TAG_PAYLOAD_LENGTH64)
730+
{
731+
// FIXME: 64bit data size in memory?
732+
[self didClose];
733+
}
734+
else if (tag == TAG_MSG_WITH_LENGTH)
735+
{
736+
NSUInteger msgLength = [data length];
737+
if (nextFrameMasked && maskingKey) {
738+
NSMutableData *masked = data.mutableCopy;
739+
UInt8 *pData = (UInt8 *)masked.mutableBytes;
740+
UInt8 *pMask = (UInt8 *)maskingKey.bytes;
741+
for (NSUInteger i = 0; i < msgLength; i++)
742+
{
743+
pData[i] = pData[i] ^ pMask[i % 4];
744+
}
745+
data = masked;
746+
}
747+
if (nextOpCode == WS_OP_TEXT_FRAME)
748+
{
749+
NSString *msg = [[NSString alloc] initWithBytes:[data bytes] length:msgLength encoding:NSUTF8StringEncoding];
750+
[self didReceiveMessage:msg];
751+
}
752+
else
753+
{
754+
[self didClose];
755+
return;
756+
}
757+
758+
// Read next frame
759+
[asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_PREFIX];
760+
}
761+
else if (tag == TAG_MSG_MASKING_KEY)
762+
{
763+
maskingKey = data.copy;
764+
}
562765
else
563766
{
564767
NSUInteger msgLength = [data length] - 1; // Excluding ending 0xFF frame

0 commit comments

Comments
 (0)