-
Notifications
You must be signed in to change notification settings - Fork 24.8k
[Websocket] Update options parameter to headers. Update to spec. #6016
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -234,7 +234,7 @@ @implementation RCTSRWebSocket | |||||||||||||||||||||||||||
__strong RCTSRWebSocket *_selfRetain; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
NSArray<NSString *> *_requestedProtocols; | ||||||||||||||||||||||||||||
NSDictionary<NSString *, NSString *> *_requestedOptions; | ||||||||||||||||||||||||||||
NSDictionary<NSString *, NSString *> *_requestedHeaders; | ||||||||||||||||||||||||||||
RCTSRIOConsumerPool *_consumerPool; | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
|
@@ -245,7 +245,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 headers:(NSDictionary<NSString *, NSString *> *)headers | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since NSURLRequest already includes headers, is there any reason for the seperate headers parameter? Can't we just include them in the request? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @nicklockwood That makes sense but it appears there are two other places that headers are being set.
So im not sure the best way to handle this. |
||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||
RCTAssertParam(request); | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
|
@@ -254,7 +254,7 @@ - (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NS | |||||||||||||||||||||||||||
_urlRequest = request; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
_requestedProtocols = [protocols copy]; | ||||||||||||||||||||||||||||
_requestedOptions = [options copy]; | ||||||||||||||||||||||||||||
_requestedHeaders= [headers copy]; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
[self _RCTSR_commonInit]; | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
@@ -265,20 +265,20 @@ - (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 headers: nil]; | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
- (instancetype)initWithURL:(NSURL *)URL; | ||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||
return [self initWithURL:URL protocols:nil options:nil]; | ||||||||||||||||||||||||||||
return [self initWithURL:URL protocols:nil headers:nil]; | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
- (instancetype)initWithURL:(NSURL *)URL protocols:(NSArray<NSString *> *)protocols; | ||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||
return [self initWithURL:URL protocols:protocols options:nil]; | ||||||||||||||||||||||||||||
return [self initWithURL:URL protocols:protocols headers:nil]; | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
- (instancetype)initWithURL:(NSURL *)URL protocols:(NSArray<NSString *> *)protocols options:(NSDictionary<NSString *, id> *)options | ||||||||||||||||||||||||||||
- (instancetype)initWithURL:(NSURL *)URL protocols:(NSArray<NSString *> *)protocols headers:(NSDictionary<NSString *, id> *)headers | ||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||
NSMutableURLRequest *request; | ||||||||||||||||||||||||||||
if (URL) { | ||||||||||||||||||||||||||||
|
@@ -297,7 +297,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 headers:headers]; | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
- (void)_RCTSR_commonInit; | ||||||||||||||||||||||||||||
|
@@ -492,7 +492,22 @@ - (void)didConnect | |||||||||||||||||||||||||||
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Protocol"), (__bridge CFStringRef)[_requestedProtocols componentsJoinedByString:@", "]); | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Origin"), (__bridge CFStringRef)(_requestedOptions[@"origin"] ?: _url.RCTSR_origin)); | ||||||||||||||||||||||||||||
if (_requestedHeaders) { | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
if (!_requestedHeaders[@"origin"]) { | ||||||||||||||||||||||||||||
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("origin"), (__bridge CFStringRef)(_url.RCTSR_origin)); | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
[_requestedHeaders enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { | ||||||||||||||||||||||||||||
if ([obj description]) { | ||||||||||||||||||||||||||||
CFHTTPMessageSetHeaderFieldValue(request, (__bridge CFStringRef)key, (__bridge CFStringRef)obj); | ||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||
RCTSRFastLog(@"Ignoring passed in header: %@, value not a string.", key); | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
}]; | ||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("origin"), (__bridge CFStringRef)(_url.RCTSR_origin)); | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cc @nicklockwood As my Obj-C fu is not great :) |
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
[_urlRequest.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { | ||||||||||||||||||||||||||||
CFHTTPMessageSetHeaderFieldValue(request, (__bridge CFStringRef)key, (__bridge CFStringRef)obj); | ||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,9 +44,9 @@ - (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]; | ||
RCTSRWebSocket *webSocket = [[RCTSRWebSocket alloc] initWithURL:URL protocols:protocols headers:headers]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can just merge the url and headers into an NSURLRequest at this point, and use the other constructor.
|
||
webSocket.delegate = self; | ||
webSocket.reactTag = socketID; | ||
if (!_sockets) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
|
@@ -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(); | ||
|
||
|
@@ -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)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. n00b question: should this be "Origin" via the spec? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AFAIK, http headers are case-insensitive and get lowercased automatically when being sent down with the request. |
||
} | ||
|
||
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() { | ||
|
@@ -188,4 +201,37 @@ private void notifyWebSocketFailed(int id, String message) { | |
params.putString("message", message); | ||
sendEvent("websocketFailed", params); | ||
} | ||
|
||
/** | ||
* Set a default origin | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please explain what setting a default origin means? |
||
* | ||
* @param Websocket connection endpoint | ||
* @return A string of the endpoint converted to HTTP protocol | ||
*/ | ||
|
||
private static String setDefaultOrigin(String uri) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I cannot tell what this does based on the name. Can you add short Javadoc please? |
||
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."); | ||
} | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah this used to be called options but it's really HTTP headers?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, these were recently merged via 9b87e6c
I noticed that his original implementation did have an option for using headers but was asked to remove it because only the
origin
header was required by the contributor.