Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
WebSocket client for Cocoa
Objective-C C Ruby
tree: c13bf8c14b

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
PKWebSocket.xcodeproj
PKWebSocket
PKWebSocketTests
Submodules
Vendor/OCMock-2.0
.gitignore
.gitmodules
LICENCE.md
README.md

README.md

PKWebSocket / WebSocket client for Cocoa

Implementation of the WebSocket protocol on top of the CocoaAsyncSocket for Cocoa. I used Zimt and cocoa-websocket project as basic for the this re-implementation.

I wanted to support multiple versions of the WebSocket protocol, make possible to easily add new protocol versions and to be able to influence handshake requests and so on.

Project is done as Static library which makes it usable in ARC/Non-ARC environments.

Architecture

I follow the terms in the specification to divide project in to the three layers.

  1. High-level public API defined in the PKWebSocket. At this layer you work with the messages which you send and receive. PKWebSocketMessage is an envelope object to be possible add binary messages for the RFC6455 version of the protocol.

All API at this layer is PUBLIC.

  1. Handlers layer where handshakes & frames are handled and translated to messaeges. Also socket connection is here to read/write frames.

All API at this layer is PRIVATE.

  1. Frame parsers layer implements actual parsing of the raw data from sockets. Validates frames and sends them to the Handler layer.

All API at this layer is PRIVATE.

Utilities

There are few utility classes:

  • PKHTTPResponse - encapsulate HTTP response
  • PKHTTPRequest - encapsulate HTTP request
  • PKWebSocketURL - NSURL sub-class making sure of correct parsing WebSocket URLs
  • PKWebSocketMessage - Wrapper around Data or String for compatibility
  • Crypto & Base64 categories

Extensibility

In order to add new protocol version there are 2 classes to implement.

If version introduce new handshake (opening/closing) a sub-class of the PKWebSocketHandler class is necessary You only need to override handshake frame methods:

- (BOOL)validateHandshakeResponse:(PKHTTPResponse *)response error:(NSError **)outError;
- (PKHTTPRequest *)handshakeRequestWithURL:(PKWebSocketURL *)anURL error:(NSError **)outError;
- (NSData *)handshakeResponseFrameBoundary;

You can add headers to your handshake request and validate your handshake response by overriding the appropriate methods.

If version introduce new framing you need to implement that framing in new PKWebSocketFrameParser sub-class. You should override init method and especially methods:

- (void)processData:(NSData *)data;
- (NSData *)textFramePayloadWithString:(NSString *)string;
- (NSData *)binaryFramePayloadWithData:(NSData *)aData;

Test suite

Project has a test suite. Most of the tests are Unit tests of the separate classes but for PKWebSocket there are bunch of the integration tests which requires you to be connected to internet as it connects to ws://echo.websocket.org.

Compatibility

Following WebSocket protocol versions are currently supported. Also I've tested on the following servers. Secure WebSockets using TLS are supported.

Protocols

  • Hixie 75 (Full support)
  • Hixie 76 (Full support)
  • TODO - RFC6455 (WIP - framing needs to be done)

Servers

  • em-websocket
  • ws://echo.websocket.org
  • TODO - Socket.IO & Node.js

Usage

Here is basic use case. Refer to the test suite for the PKWebSocket - PKWebSocketTests/PKWebSocketTests.m - for more info.

#import "PKWebSocket.h"
#import "PKWebSocketMessage.h"
#import "PKWebSocketHandler-Hixie76.h"

NSString *url = @"ws://echo.websocket.org";
PKWebSocketHandlerHixie76 *handler = [[PKWebSocketHandlerHixie76 alloc] init];
PKWebSocket *ws = [[PKWebSocket alloc] initWithHandler:handler delegate:self];

NSError *error;
if ([ws openWithURLString:url error:&error]) {
  [ws send:[PKWebSocketMessage messageWithString:@"string to send"]];
  ...
  ...
}

Delegate methods

On the delegate WebSocket calls following methods if you opt for them:

- (void)webSocket:(PKWebSocket *)webSocket didFailWithError:(NSError *)error;
- (void)webSocketDidOpen:(PKWebSocket *)webSocket;
- (void)webSocketDidClose:(PKWebSocket *)webSocket;
- (void)webSocket:(PKWebSocket *)webSocket didReceiveMessage:(PKWebSocketMessage *)message;
- (void)webSocketDidSendMessage:(PKWebSocket *)webSocket;

Using secure WebSocket

In order to use secure WebSocket you need to use wss URL scheme and you will probably need to set some TLS settings.

NSMutableDictionary *tlsSettings = [NSMutableDictionary dictionaryWithCapacity:4];
[tlsSettings setObject:url.host forKey:(NSString *)kCFStreamSSLPeerName];

// Allow expired certificates
[tlsSettings setObject:[NSNumber numberWithBool:YES]
                forKey:(NSString *)kCFStreamSSLAllowsExpiredCertificates];

// Allow self-signed certificates
[tlsSettings setObject:[NSNumber numberWithBool:YES]
                forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];

// In fact, don't even validate the certificate chain
[tlsSettings setObject:[NSNumber numberWithBool:NO]
                forKey:(NSString *)kCFStreamSSLValidatesCertificateChain];

// Set it to the web socket
[websocket setTLSSetting:tlsSettings];

Requirements & Dependencies & Submodules

Get code & Contribute

I'm grateful for any contributions no matter if it's bug report or patch!

Code

If you have GIT 1.7+ ...

git clone git@github.com:pk/PKWebSocket.git --recursive

or, earlier...

git clone git@github.com:pk/PKWebSocket.git
cd PKWebSocket
git submodule init
git submodule update

Adding to your project

You can add PKWebSocket to your project in two ways.

XCode 4.x sub-project

  1. Drag-Drop PKWebSocket.xcodeproj in your project
  2. Add libPKWebSocket.a to your Link Binary With Libraries You might need to add CFNetwork.framework as well.
  3. Add -ObjC and -all_load to your Other Linker Flags
  4. Add $(BUILT_PRODUCTS_DIR) to your Libray Search Paths & Header Search Paths, mark recursive

Now you should be able to compile your project with the PKWebSocket. You can validate settings by going to the Derived data folder where you should see libPKWebSocket.a and PKWebSocket directory with header files.

Get the static library binary release (TODO)

I first need to push the release.

Based on the projects

Something went wrong with that request. Please try again.