Skip to content
This repository has been archived by the owner on Feb 18, 2019. It is now read-only.

Commit

Permalink
Update options parameter to headers. Update to spec.
Browse files Browse the repository at this point in the history
Summary:This is a follow up of facebook@9b87e6c.

- Allows custom headers on connection request
- Adds a default `origin` header to Android, just like iOS

**Introduces no breaking changes.**

I was working on something similar and would like to propose a few changes that make the API more consistent across both iOS and Android platforms and brings this closer to [spec](https://tools.ietf.org/html/rfc6455).

I believe aprock first implementation of adding custom `headers` was correct. It makes sense naming this argument `headers` since we have no other general options available, and the current `options` field is being used to pass in a header anyway.

My use case for custom headers was attaching a token to the `Authorization` header on the connection request. I have been testing this by passing a JWT inside the `Authorization` header and verifying it on the server before establishing a connection.
Closes facebook#6016

Differential Revision: D3040735

Pulled By: nicklockwood

fb-gh-sync-id: f81bd14ccbdba36309b9d4b4850fb66fe4deae11
shipit-source-id: f81bd14ccbdba36309b9d4b4850fb66fe4deae11
  • Loading branch information
christopherdro authored and Facebook Github Bot 6 committed Mar 15, 2016
1 parent 79d6ced commit 205b5d4
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 30 deletions.
8 changes: 3 additions & 5 deletions Libraries/WebSocket/RCTSRWebSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,17 @@ extern NSString *const RCTSRHTTPResponseErrorKey;
@property (nonatomic, readonly, copy) NSString *protocol;

// Protocols should be an array of strings that turn into Sec-WebSocket-Protocol.
// options can contain a custom "origin" NSString
- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NSString *> *)protocols options:(NSDictionary<NSString *, NSString *> *)options NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NSString *> *)protocols NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithURLRequest:(NSURLRequest *)request;

// Some helper constructors.
- (instancetype)initWithURL:(NSURL *)url protocols:(NSArray<NSString *> *)protocols options:(NSDictionary<NSString *, NSString *> *)options;
- (instancetype)initWithURL:(NSURL *)url protocols:(NSArray<NSString *> *)protocols;
- (instancetype)initWithURL:(NSURL *)url;

// Delegate queue will be dispatch_main_queue by default.
// You cannot set both OperationQueue and dispatch_queue.
- (void)setDelegateOperationQueue:(NSOperationQueue*) queue;
- (void)setDelegateDispatchQueue:(dispatch_queue_t) queue;
- (void)setDelegateOperationQueue:(NSOperationQueue *)queue;
- (void)setDelegateDispatchQueue:(dispatch_queue_t)queue;

// By default, it will schedule itself on +[NSRunLoop RCTSR_networkRunLoop] using defaultModes.
- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
Expand Down
19 changes: 6 additions & 13 deletions Libraries/WebSocket/RCTSRWebSocket.m
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,6 @@ @implementation RCTSRWebSocket
__strong RCTSRWebSocket *_selfRetain;

NSArray<NSString *> *_requestedProtocols;
NSDictionary<NSString *, NSString *> *_requestedOptions;
RCTSRIOConsumerPool *_consumerPool;
}

Expand All @@ -245,7 +244,7 @@ + (void)initialize;
CRLFCRLF = [[NSData alloc] initWithBytes:"\r\n\r\n" length:4];
}

- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NSString *> *)protocols options:(NSDictionary<NSString *, NSString *> *)options
- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NSString *> *)protocols
{
RCTAssertParam(request);

Expand All @@ -254,7 +253,6 @@ - (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NS
_urlRequest = request;

_requestedProtocols = [protocols copy];
_requestedOptions = [options copy];

[self _RCTSR_commonInit];
}
Expand All @@ -265,20 +263,15 @@ - (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NS

- (instancetype)initWithURLRequest:(NSURLRequest *)request;
{
return [self initWithURLRequest:request protocols:nil options: nil];
return [self initWithURLRequest:request protocols:nil];
}

- (instancetype)initWithURL:(NSURL *)URL;
{
return [self initWithURL:URL protocols:nil options:nil];
return [self initWithURL:URL protocols:nil];
}

- (instancetype)initWithURL:(NSURL *)URL protocols:(NSArray<NSString *> *)protocols;
{
return [self initWithURL:URL protocols:protocols options:nil];
}

- (instancetype)initWithURL:(NSURL *)URL protocols:(NSArray<NSString *> *)protocols options:(NSDictionary<NSString *, id> *)options
{
NSMutableURLRequest *request;
if (URL) {
Expand All @@ -297,7 +290,7 @@ - (instancetype)initWithURL:(NSURL *)URL protocols:(NSArray<NSString *> *)protoc
NSArray<NSHTTPCookie *> *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:components.URL];
[request setAllHTTPHeaderFields:[NSHTTPCookie requestHeaderFieldsWithCookies:cookies]];
}
return [self initWithURLRequest:request protocols:protocols options:options];
return [self initWithURLRequest:request protocols:protocols];
}

- (void)_RCTSR_commonInit;
Expand Down Expand Up @@ -488,12 +481,12 @@ - (void)didConnect
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Key"), (__bridge CFStringRef)_secKey);
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Version"), (__bridge CFStringRef)[NSString stringWithFormat:@"%ld", (long)_webSocketVersion]);

CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Origin"), (__bridge CFStringRef)_url.RCTSR_origin);

if (_requestedProtocols) {
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Protocol"), (__bridge CFStringRef)[_requestedProtocols componentsJoinedByString:@", "]);
}

CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Origin"), (__bridge CFStringRef)(_requestedOptions[@"origin"] ?: _url.RCTSR_origin));

[_urlRequest.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
CFHTTPMessageSetHeaderFieldValue(request, (__bridge CFStringRef)key, (__bridge CFStringRef)obj);
}];
Expand Down
10 changes: 8 additions & 2 deletions Libraries/WebSocket/RCTWebSocketModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#import "RCTBridge.h"
#import "RCTEventDispatcher.h"
#import "RCTConvert.h"
#import "RCTUtils.h"

@implementation RCTSRWebSocket (React)
Expand Down Expand Up @@ -44,9 +45,14 @@ - (void)dealloc
}
}

RCT_EXPORT_METHOD(connect:(NSURL *)URL protocols:(NSArray *)protocols options:(NSDictionary *)options socketID:(nonnull NSNumber *)socketID)
RCT_EXPORT_METHOD(connect:(NSURL *)URL protocols:(NSArray *)protocols headers:(NSDictionary *)headers socketID:(nonnull NSNumber *)socketID)
{
RCTSRWebSocket *webSocket = [[RCTSRWebSocket alloc] initWithURL:URL protocols:protocols options:options];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
[headers enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
[request addValue:[RCTConvert NSString:value] forHTTPHeaderField:key];
}];

RCTSRWebSocket *webSocket = [[RCTSRWebSocket alloc] initWithURLRequest:request protocols:protocols];
webSocket.delegate = self;
webSocket.reactTag = socketID;
if (!_sockets) {
Expand Down
4 changes: 2 additions & 2 deletions Libraries/WebSocket/WebSocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ class WebSocket extends WebSocketBase {
_socketId: number;
_subs: any;

connectToSocketImpl(url: string, protocols: ?Array<string>, options: ?{origin?: string}): void {
connectToSocketImpl(url: string, protocols: ?Array<string>, headers: ?Object): void {
this._socketId = WebSocketId++;

RCTWebSocketModule.connect(url, protocols, options, this._socketId);
RCTWebSocketModule.connect(url, protocols, headers, this._socketId);

this._registerEvents(this._socketId);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
import com.squareup.okhttp.ws.WebSocketCall;
import com.squareup.okhttp.ws.WebSocketListener;

import java.net.URISyntaxException;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -63,7 +65,7 @@ public String getName() {
}

@ReactMethod
public void connect(final String url, @Nullable final ReadableArray protocols, @Nullable final ReadableMap options, final int id) {
public void connect(final String url, @Nullable final ReadableArray protocols, @Nullable final ReadableMap headers, final int id) {
// ignoring protocols, since OKHttp overrides them.
OkHttpClient client = new OkHttpClient();

Expand All @@ -76,14 +78,25 @@ public void connect(final String url, @Nullable final ReadableArray protocols, @
.tag(id)
.url(url);

if (options != null && options.hasKey("origin")) {
if (ReadableType.String.equals(options.getType("origin"))) {
builder.addHeader("Origin", options.getString("origin"));
} else {
FLog.w(
ReactConstants.TAG,
"Ignoring: requested origin, value not a string");
if (headers != null) {
ReadableMapKeySetIterator iterator = headers.keySetIterator();

if (!headers.hasKey("origin")) {
builder.addHeader("origin", setDefaultOrigin(url));
}

while (iterator.hasNextKey()) {
String key = iterator.nextKey();
if (ReadableType.String.equals(headers.getType(key))) {
builder.addHeader(key, headers.getString(key));
} else {
FLog.w(
ReactConstants.TAG,
"Ignoring: requested " + key + ", value not a string");
}
}
} else {
builder.addHeader("origin", setDefaultOrigin(url));
}

WebSocketCall.create(client, builder.build()).enqueue(new WebSocketListener() {
Expand Down Expand Up @@ -188,4 +201,37 @@ private void notifyWebSocketFailed(int id, String message) {
params.putString("message", message);
sendEvent("websocketFailed", params);
}

/**
* Set a default origin
*
* @param Websocket connection endpoint
* @return A string of the endpoint converted to HTTP protocol
*/

private static String setDefaultOrigin(String uri) {
try {
String defaultOrigin;
String scheme = "";

URI requestURI = new URI(uri);
if (requestURI.getScheme().equals("wss")) {
scheme += "https";
} else if (requestURI.getScheme().equals("ws")) {
scheme += "http";
}

if (requestURI.getPort() != -1) {
defaultOrigin = String.format("%s://%s:%s", scheme, requestURI.getHost(), requestURI.getPort());
} else {
defaultOrigin = String.format("%s://%s/", scheme, requestURI.getHost());
}

return defaultOrigin;

} catch(URISyntaxException e) {
throw new IllegalArgumentException("Unable to set " + uri + " as default origin header.");
}
}

}

0 comments on commit 205b5d4

Please sign in to comment.