SRHTTPConnectMessage.m 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. //
  2. // Copyright (c) 2016-present, Facebook, Inc.
  3. // All rights reserved.
  4. //
  5. // This source code is licensed under the BSD-style license found in the
  6. // LICENSE file in the root directory of this source tree. An additional grant
  7. // of patent rights can be found in the PATENTS file in the same directory.
  8. //
  9. #import "SRHTTPConnectMessage.h"
  10. #import "SRURLUtilities.h"
  11. NS_ASSUME_NONNULL_BEGIN
  12. static NSString *_SRHTTPConnectMessageHost(NSURL *url)
  13. {
  14. NSString *host = url.host;
  15. if (url.port) {
  16. host = [host stringByAppendingFormat:@":%@", url.port];
  17. }
  18. return host;
  19. }
  20. CFHTTPMessageRef SRHTTPConnectMessageCreate(NSURLRequest *request,
  21. NSString *securityKey,
  22. uint8_t webSocketProtocolVersion,
  23. NSArray<NSHTTPCookie *> *_Nullable cookies,
  24. NSArray<NSString *> *_Nullable requestedProtocols)
  25. {
  26. NSURL *url = request.URL;
  27. CFHTTPMessageRef message = CFHTTPMessageCreateRequest(NULL, CFSTR("GET"), (__bridge CFURLRef)url, kCFHTTPVersion1_1);
  28. // Set host first so it defaults
  29. CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Host"), (__bridge CFStringRef)_SRHTTPConnectMessageHost(url));
  30. NSMutableData *keyBytes = [[NSMutableData alloc] initWithLength:16];
  31. int result = SecRandomCopyBytes(kSecRandomDefault, keyBytes.length, keyBytes.mutableBytes);
  32. if (result != 0) {
  33. //TODO: (nlutsenko) Check if there was an error.
  34. }
  35. // Apply cookies if any have been provided
  36. if (cookies) {
  37. NSDictionary<NSString *, NSString *> *messageCookies = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
  38. [messageCookies enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) {
  39. if (key.length && obj.length) {
  40. CFHTTPMessageSetHeaderFieldValue(message, (__bridge CFStringRef)key, (__bridge CFStringRef)obj);
  41. }
  42. }];
  43. }
  44. // set header for http basic auth
  45. NSString *basicAuthorizationString = SRBasicAuthorizationHeaderFromURL(url);
  46. if (basicAuthorizationString) {
  47. CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Authorization"), (__bridge CFStringRef)basicAuthorizationString);
  48. }
  49. CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Upgrade"), CFSTR("websocket"));
  50. CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Connection"), CFSTR("Upgrade"));
  51. CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Sec-WebSocket-Key"), (__bridge CFStringRef)securityKey);
  52. CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Sec-WebSocket-Version"), (__bridge CFStringRef)@(webSocketProtocolVersion).stringValue);
  53. CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Origin"), (__bridge CFStringRef)SRURLOrigin(url));
  54. if (requestedProtocols.count) {
  55. CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Sec-WebSocket-Protocol"),
  56. (__bridge CFStringRef)[requestedProtocols componentsJoinedByString:@", "]);
  57. }
  58. [request.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
  59. CFHTTPMessageSetHeaderFieldValue(message, (__bridge CFStringRef)key, (__bridge CFStringRef)obj);
  60. }];
  61. return message;
  62. }
  63. NS_ASSUME_NONNULL_END