Example #1
0
        protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancel)
        {
            Guard.NotNull(nameof(request), request);
            if (cancel == null)
            {
                cancel = CancellationToken.None;
            }
            // https://tools.ietf.org/html/rfc7230#section-2.7.1
            // A sender MUST NOT generate an "http" URI with an empty host identifier.
            var host = Guard.NotNullOrEmptyOrWhitespace($"{nameof(request)}.{nameof(request.RequestUri)}.{nameof(request.RequestUri.DnsSafeHost)}", request.RequestUri.DnsSafeHost, trim: true);

            using (await DisposeRequestLock.ReaderLockAsync(cancel).ConfigureAwait(false))
                using (var connectLockTask = await ConnectLock.LockAsync(cancel).ConfigureAwait(false))         // this makes sure clients with the same host don't try to connect concurrently, it gets released after connection established
                {
                    KeyValuePair <TorSocks5Client, AsyncLock> clientLockPair = TryFindClientLockPair(host, request.RequestUri.Port);
                    AsyncLock clientLock = clientLockPair.Value ?? new AsyncLock();             // this makes sure clients with the same host don't work concurrently
                    using (await clientLock.LockAsync(cancel).ConfigureAwait(false))
                    {
                        TorSocks5Client client = await SendAsync(request, host, connectLockTask, clientLockPair, clientLock, cancel);

                        try
                        {
                            return(await new HttpResponseMessage().CreateNewAsync(client.Stream, request.Method).ConfigureAwait(false));
                        }
                        catch (IOException)
                        {
                            // the connection is lost, reconnect
                            client = await SendAsync(request, host, connectLockTask, clientLockPair, clientLock, cancel);

                            return(await new HttpResponseMessage().CreateNewAsync(client.Stream, request.Method).ConfigureAwait(false));
                        }
                    }
                }
        }
Example #2
0
        protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancel)
        {
            Guard.NotNull(nameof(request), request);
            if (cancel == null)
            {
                cancel = CancellationToken.None;
            }
            // https://tools.ietf.org/html/rfc7230#section-2.7.1
            // A sender MUST NOT generate an "http" URI with an empty host identifier.
            var host = Guard.NotNullOrEmptyOrWhitespace($"{nameof(request)}.{nameof(request.RequestUri)}.{nameof(request.RequestUri.DnsSafeHost)}", request.RequestUri.DnsSafeHost, trim: true);

            using (var linuxOsxLock = await LinuxOsxLock.LockAsync(cancel).ConfigureAwait(false))             // Linux and OSX is terrible, rather do everything in sync, if windows, it'll be released right away, this must be in effect to bypass this linuxosxbug: if (client != null && (!client.IsConnected || !RuntimeInformation.IsOSPlatform(OSPlatform.Windows)))
                using (await DisposeRequestLock.ReaderLockAsync(cancel).ConfigureAwait(false))
                    using (var connectLockTask = await ConnectLock.LockAsync(cancel).ConfigureAwait(false))   // this makes sure clients with the same host don't try to connect concurrently, it gets released after connection established
                    {
                        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                        {
                            linuxOsxLock.Dispose();
                        }

                        KeyValuePair <TorSocks5Client, AsyncLock> clientLockPair = TryFindClientLockPair(host, request.RequestUri.Port);
                        AsyncLock clientLock = clientLockPair.Value ?? new AsyncLock();         // this makes sure clients with the same host don't work concurrently
                        using (await clientLock.LockAsync(cancel).ConfigureAwait(false))
                        {
                            TorSocks5Client client = await SendAsync(request, host, connectLockTask, clientLockPair, clientLock, cancel);

                            try
                            {
                                return(await new HttpResponseMessage().CreateNewAsync(client.Stream, request.Method).ConfigureAwait(false));
                            }
                            catch (IOException)
                            {
                                // the connection is lost, reconnect
                                client = await SendAsync(request, host, connectLockTask, clientLockPair, clientLock, cancel);

                                return(await new HttpResponseMessage().CreateNewAsync(client.Stream, request.Method).ConfigureAwait(false));
                            }
                        }
                    }
        }