<commit_before>//
//  CBLWebSocket.m
//  StreamTaskTest
//
//  Created by <NAME> on 3/14/17.
//  Copyright © 2017 Couchbase. All rights reserved.
//

#import "CBLWebSocket.h"
#import "CBLHTTPLogic.h"
#import "CBLTrustCheck.h"
#import "CBLCoreBridge.h"
#import "CBLStatus.h"
#import "CBLReplicatorConfiguration.h"  // for the options constants
#import "CBLLog.h"
#import "CBLReplicator+Internal.h"
#import "c4Socket.h"
#import <CommonCrypto/CommonDigest.h>
#import <dispatch/dispatch.h>
#import <memory>
#import <netdb.h>

extern "C" {
#import "MYAnonymousIdentity.h"
}

using namespace fleece;
using namespace fleeceapi;

static constexpr size_t kMaxReceivedBytesPending = 100 * 1024;
static constexpr NSTimeInterval kConnectTimeout = 15.0;
static constexpr NSTimeInterval kIdleTimeout = 300.0;


@interface CBLWebSocket ()
@property (readwrite, atomic) NSString* protocol;
@end


@implementation CBLWebSocket
{
    AllocedDict _options;
    NSOperationQueue* _queue;
    dispatch_queue_t _c4Queue;
    NSURLSession* _session;
    NSURLSessionStreamTask *_task;
    NSString* _expectedAcceptHeader;
    NSArray* _protocols;
    CBLHTTPLogic* _logic;
    NSString* _clientCertID;
    C4Socket* _c4socket;
    NSError* _authError;
    BOOL _receiving;
    size_t _receivedBytesPending, _sentBytesPending;
    CFAbsoluteTime _lastReadTime;
}

@synthesize protocol=_protocol;


#define Log(FMT, ...)        CBLLog(       WS, @"" FMT, ##__VA_ARGS__)
#define LogVerbose(FMT, ...) CBLLogVerbose(WS, @"" FMT, ##__VA_ARGS__)
#define Warn(FMT, ...)       CBLWarn(      WS, @"" FMT, ##__VA_ARGS__)


+ (void) registerWithC4 {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        c4socket_registerFactory({
            .providesWebSockets = false,
            .open = &doOpen,
            .close = &doClose,
            .write = &doWrite,
            .completedReceive = &doCompletedReceive
        });
        CBLLog(WebSocket, @"CBLWebSocket registered as C4SocketFactory");
    });
}

static void doOpen(C4Socket* s, const C4Address* addr, C4Slice optionsFleece) {
    NSURLComponents* c = [NSURLComponents new];
    if (addr->scheme == "blips"_sl || addr->scheme == "wss"_sl)
        c.scheme = @"https";
    else
        c.scheme = @"http";
    c.host = slice2string(addr->hostname);
    c.port = @(addr->port);
    c.path = slice2string(addr->path);
    NSURL* url = c.URL;
    if (!url) {
        c4socket_closed(s, {LiteCoreDomain, kC4ErrorInvalidParameter});
        return;
    }
    auto socket = [[CBLWebSocket alloc] initWithURL: url c4socket: s options: optionsFleece];
    s->nativeHandle = (__bridge void*)socket;
    [socket start];
}

static void doClose(C4Socket* s) {
    [(__bridge CBLWebSocket*)s->nativeHandle closeSocket];
}

static void doWrite(C4Socket* s, C4SliceResult allocatedData) {
    [(__bridge CBLWebSocket*)s->nativeHandle writeAndFree: allocatedData];
}

static void doCompletedReceive(C4Socket* s, size_t byteCount) {
    [(__bridge CBLWebSocket*)s->nativeHandle completedReceive: byteCount];
}


- (instancetype) initWithURL: (NSURL*)url c4socket: (C4Socket*)c4socket options: (slice)options {
    self = [super init];
    if (self) {
        _c4socket = c4socket;
        _options = AllocedDict(options);

        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: url];
        _logic = [[CBLHTTPLogic alloc] initWithURLRequest: request];
        _logic.handleRedirects = YES;

        [self setupAuth];

        _queue = [[NSOperationQueue alloc] init];
        _queue.maxConcurrentOperationCount = 1;     // make it serial!
        _queue.name = [NSString stringWithFormat: @"WebSocket to %@:%u", url.host, _logic.port];

        _c4Queue = dispatch_queue_create("Websocket C4 dispatch", DISPATCH_QUEUE_SERIAL);

        NSURLSessionConfiguration* conf = [NSURLSessionConfiguration defaultSessionConfiguration];
        conf.HTTPShouldSetCookies = NO;
        conf.HTTPCookieStorage = nil;
        conf.URLCache = nil;
        _session = [NSURLSession sessionWithConfiguration: conf
                                                 delegate: self
                                            delegateQueue: _queue];
    }
    return self;
}
<commit_msg>Fix session cookie overwritten by the cookie in shared storage (#1943)<commit_after>//
//  CBLWebSocket.m
//  StreamTaskTest
//
//  Created by <NAME> on 3/14/17.
//  Copyright © 2017 Couchbase. All rights reserved.
//

#import "CBLWebSocket.h"
#import "CBLHTTPLogic.h"
#import "CBLTrustCheck.h"
#import "CBLCoreBridge.h"
#import "CBLStatus.h"
#import "CBLReplicatorConfiguration.h"  // for the options constants
#import "CBLLog.h"
#import "CBLReplicator+Internal.h"
#import "c4Socket.h"
#import <CommonCrypto/CommonDigest.h>
#import <dispatch/dispatch.h>
#import <memory>
#import <netdb.h>

extern "C" {
#import "MYAnonymousIdentity.h"
}

using namespace fleece;
using namespace fleeceapi;

static constexpr size_t kMaxReceivedBytesPending = 100 * 1024;
static constexpr NSTimeInterval kConnectTimeout = 15.0;
static constexpr NSTimeInterval kIdleTimeout = 300.0;


@interface CBLWebSocket ()
@property (readwrite, atomic) NSString* protocol;
@end


@implementation CBLWebSocket
{
    AllocedDict _options;
    NSOperationQueue* _queue;
    dispatch_queue_t _c4Queue;
    NSURLSession* _session;
    NSURLSessionStreamTask *_task;
    NSString* _expectedAcceptHeader;
    NSArray* _protocols;
    CBLHTTPLogic* _logic;
    NSString* _clientCertID;
    C4Socket* _c4socket;
    NSError* _authError;
    BOOL _receiving;
    size_t _receivedBytesPending, _sentBytesPending;
    CFAbsoluteTime _lastReadTime;
}

@synthesize protocol=_protocol;


#define Log(FMT, ...)        CBLLog(       WS, @"" FMT, ##__VA_ARGS__)
#define LogVerbose(FMT, ...) CBLLogVerbose(WS, @"" FMT, ##__VA_ARGS__)
#define Warn(FMT, ...)       CBLWarn(      WS, @"" FMT, ##__VA_ARGS__)


+ (void) registerWithC4 {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        c4socket_registerFactory({
            .providesWebSockets = false,
            .open = &doOpen,
            .close = &doClose,
            .write = &doWrite,
            .completedReceive = &doCompletedReceive
        });
        CBLLog(WebSocket, @"CBLWebSocket registered as C4SocketFactory");
    });
}

static void doOpen(C4Socket* s, const C4Address* addr, C4Slice optionsFleece) {
    NSURLComponents* c = [NSURLComponents new];
    if (addr->scheme == "blips"_sl || addr->scheme == "wss"_sl)
        c.scheme = @"https";
    else
        c.scheme = @"http";
    c.host = slice2string(addr->hostname);
    c.port = @(addr->port);
    c.path = slice2string(addr->path);
    NSURL* url = c.URL;
    if (!url) {
        c4socket_closed(s, {LiteCoreDomain, kC4ErrorInvalidParameter});
        return;
    }
    auto socket = [[CBLWebSocket alloc] initWithURL: url c4socket: s options: optionsFleece];
    s->nativeHandle = (__bridge void*)socket;
    [socket start];
}

static void doClose(C4Socket* s) {
    [(__bridge CBLWebSocket*)s->nativeHandle closeSocket];
}

static void doWrite(C4Socket* s, C4SliceResult allocatedData) {
    [(__bridge CBLWebSocket*)s->nativeHandle writeAndFree: allocatedData];
}

static void doCompletedReceive(C4Socket* s, size_t byteCount) {
    [(__bridge CBLWebSocket*)s->nativeHandle completedReceive: byteCount];
}


- (instancetype) initWithURL: (NSURL*)url c4socket: (C4Socket*)c4socket options: (slice)options {
    self = [super init];
    if (self) {
        _c4socket = c4socket;
        _options = AllocedDict(options);

        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: url];
        request.HTTPShouldHandleCookies = NO;
        _logic = [[CBLHTTPLogic alloc] initWithURLRequest: request];
        _logic.handleRedirects = YES;

        [self setupAuth];

        _queue = [[NSOperationQueue alloc] init];
        _queue.maxConcurrentOperationCount = 1;     // make it serial!
        _queue.name = [NSString stringWithFormat: @"WebSocket to %@:%u", url.host, _logic.port];

        _c4Queue = dispatch_queue_create("Websocket C4 dispatch", DISPATCH_QUEUE_SERIAL);

        NSURLSessionConfiguration* conf = [NSURLSessionConfiguration defaultSessionConfiguration];
        conf.HTTPShouldSetCookies = NO;
        conf.HTTPCookieStorage = nil;
        conf.URLCache = nil;
        _session = [NSURLSession sessionWithConfiguration: conf
                                                 delegate: self
                                            delegateQueue: _queue];
    }
    return self;
}

{'fraction_non_alphanumeric': 0.11338398597311514, 'fraction_numerical': 0.012156633547632963, 'mean_word_length': 3.2801400700350176, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5443022', 'n_tokens_mistral': 2855, 'n_tokens_neox': 2732, 'n_words': 618}