예제 #1
0
        /// <summary>
        /// Registers a callback for the <paramref name="cancellationToken"/> that blocks calls to <see cref="CancellationTokenSource.Cancel()"/> until <see cref="Dispose"/> has been called.
        /// </summary>
        /// <param name="cancellationToken">Used to signal cancellation requests.</param>
        public CancellationGuard(CancellationToken cancellationToken)
        {
            _registration = cancellationToken.Register(
#if NET40 || NET45
                _tcs.Task.Wait
#else
                () => _event.WaitOne()
#endif
            );
        }
예제 #2
0
        /// <summary>
        /// Registers a callback for the <paramref name="cancellationToken"/> that blocks calls to <see cref="CancellationTokenSource.Cancel()"/> until <see cref="Dispose"/> has been called.
        /// </summary>
        /// <param name="cancellationToken">Used to signal cancellation requests.</param>
        /// <param name="timeout">A timespan after which the cancellation will be considered completed even if <see cref="Dispose"/> has not been called yet.</param>
        public CancellationGuard(CancellationToken cancellationToken, TimeSpan timeout)
        {
            _registration = cancellationToken.Register(
#if NET40 || NET45
                () => _tcs.Task.Wait(timeout)
#else
                () =>
                {
                    _event.WaitOne(timeout, exitContext: true);
                    _event.Close();
                }
#endif
            );
        }
예제 #3
0
        public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options)
        {
            _operation.InterlockedCheckAndUpdateState(WebSocketState.Connecting, s_validConnectStates);

            using (CancellationTokenRegistration ctr = ThrowOrRegisterCancellation(cancellationToken))
            {
                lock (_operation.Lock)
                {
                    _operation.CheckValidState(s_validConnectingStates);

                    // Must grab lock until RequestHandle is populated, otherwise we risk resource leaks on Abort.
                    //
                    // TODO (Issue 2506): Alternatively, release the lock between WinHTTP operations and check, under lock, that the
                    // state is still valid to continue operation.
                    _operation.SessionHandle = InitializeWinHttp(options);

                    _operation.ConnectionHandle = Interop.WinHttp.WinHttpConnectWithCallback(
                        _operation.SessionHandle,
                        uri.IdnHost,
                        (ushort)uri.Port,
                        0);

                    ThrowOnInvalidHandle(_operation.ConnectionHandle);

                    bool secureConnection = uri.Scheme == UriScheme.Https || uri.Scheme == UriScheme.Wss;

                    _operation.RequestHandle = Interop.WinHttp.WinHttpOpenRequestWithCallback(
                        _operation.ConnectionHandle,
                        "GET",
                        uri.PathAndQuery,
                        null,
                        Interop.WinHttp.WINHTTP_NO_REFERER,
                        null,
                        secureConnection ? Interop.WinHttp.WINHTTP_FLAG_SECURE : 0);

                    ThrowOnInvalidHandle(_operation.RequestHandle);

                    if (!Interop.WinHttp.WinHttpSetOption(
                            _operation.RequestHandle,
                            Interop.WinHttp.WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET,
                            IntPtr.Zero,
                            0))
                    {
                        WinHttpException.ThrowExceptionUsingLastError();
                    }

                    // We need the address of the IntPtr to the GCHandle.
                    IntPtr context = _operation.ToIntPtr();
                    IntPtr contextAddress;
                    unsafe
                    {
                        contextAddress = (IntPtr)(void *)&context;
                    }

                    if (!Interop.WinHttp.WinHttpSetOption(
                            _operation.RequestHandle,
                            Interop.WinHttp.WINHTTP_OPTION_CONTEXT_VALUE,
                            contextAddress,
                            (uint)IntPtr.Size))
                    {
                        WinHttpException.ThrowExceptionUsingLastError();
                    }

                    if (Interop.WinHttp.WinHttpSetStatusCallback(
                            _operation.RequestHandle,
                            WinHttpWebSocketCallback.s_StaticCallbackDelegate,
                            Interop.WinHttp.WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS,
                            IntPtr.Zero) == (IntPtr)Interop.WinHttp.WINHTTP_INVALID_STATUS_CALLBACK)
                    {
                        WinHttpException.ThrowExceptionUsingLastError();
                    }

                    _operation.RequestHandle.AttachCallback();

                    AddRequestHeaders(uri, options);

                    _operation.TcsUpgrade = new TaskCompletionSource <bool>();
                }

                await InternalSendWsUpgradeRequestAsync().ConfigureAwait(false);

                await InternalReceiveWsUpgradeResponse().ConfigureAwait(false);

                lock (_operation.Lock)
                {
                    VerifyUpgradeResponse();

                    ThrowOnInvalidConnectState();

                    _operation.WebSocketHandle =
                        Interop.WinHttp.WinHttpWebSocketCompleteUpgrade(_operation.RequestHandle, IntPtr.Zero);

                    ThrowOnInvalidHandle(_operation.WebSocketHandle);

                    // We need the address of the IntPtr to the GCHandle.
                    IntPtr context = _operation.ToIntPtr();
                    IntPtr contextAddress;
                    unsafe
                    {
                        contextAddress = (IntPtr)(void *)&context;
                    }

                    if (!Interop.WinHttp.WinHttpSetOption(
                            _operation.WebSocketHandle,
                            Interop.WinHttp.WINHTTP_OPTION_CONTEXT_VALUE,
                            contextAddress,
                            (uint)IntPtr.Size))
                    {
                        WinHttpException.ThrowExceptionUsingLastError();
                    }

                    _operation.WebSocketHandle.AttachCallback();
                    _operation.UpdateState(WebSocketState.Open);

                    if (_operation.RequestHandle != null)
                    {
                        _operation.RequestHandle.Dispose();
                        // RequestHandle will be set to null in the callback.
                    }
                    _operation.TcsUpgrade = null;

                    ctr.Dispose();
                }
            }
        }
예제 #4
0
        private async ValueTask <FlushResult> FlushAsyncInternal(bool writeToStream, ReadOnlyMemory <byte> data, CancellationToken cancellationToken = default)
        {
            // Write all completed segments and whatever remains in the current segment
            // and flush the result.
            CancellationTokenRegistration reg = default;

            if (cancellationToken.CanBeCanceled)
            {
                reg = cancellationToken.UnsafeRegister(state => ((StreamPipeWriter)state !).Cancel(), this);
            }

            if (_tailBytesBuffered > 0)
            {
                Debug.Assert(_tail != null);

                // Update any buffered data
                _tail.End         += _tailBytesBuffered;
                _tailBytesBuffered = 0;
            }

            using (reg)
            {
                CancellationToken localToken = InternalTokenSource.Token;
                try
                {
                    BufferSegment?segment = _head;
                    while (segment != null)
                    {
                        BufferSegment returnSegment = segment;
                        segment = segment.NextSegment;

                        if (returnSegment.Length > 0 && writeToStream)
                        {
                            await InnerStream.WriteAsync(returnSegment.Memory, localToken).ConfigureAwait(false);
                        }

                        returnSegment.ResetMemory();
                        ReturnSegmentUnsynchronized(returnSegment);

                        // Update the head segment after we return the current segment
                        _head = segment;
                    }

                    if (writeToStream)
                    {
                        // Write data after the buffered data
                        if (data.Length > 0)
                        {
                            await InnerStream.WriteAsync(data, localToken).ConfigureAwait(false);
                        }

                        if (_bytesBuffered > 0 || data.Length > 0)
                        {
                            await InnerStream.FlushAsync(localToken).ConfigureAwait(false);
                        }
                    }

                    // Mark bytes as written *after* flushing
                    _head          = null;
                    _tail          = null;
                    _tailMemory    = default;
                    _bytesBuffered = 0;

                    return(new FlushResult(isCanceled: false, isCompleted: false));
                }
                catch (OperationCanceledException)
                {
                    // Remove the cancellation token such that the next time Flush is called
                    // A new CTS is created.
                    lock (_lockObject)
                    {
                        _internalTokenSource = null;
                    }

                    if (localToken.IsCancellationRequested && !cancellationToken.IsCancellationRequested)
                    {
                        // Catch cancellation and translate it into setting isCanceled = true
                        return(new FlushResult(isCanceled: true, isCompleted: false));
                    }

                    throw;
                }
            }
        }
예제 #5
0
 public Data(TaskCompletionSource <bool> source, Action <object> cancel)
 {
     Source       = source;
     Cancel       = cancel;
     Registration = default;
 }
예제 #6
0
            private async Task AcceptAsync(CancellationToken shutdownSignal)
            {
                object connectionCountLock = new object();
                int    openConnections     = 0;
                TaskCompletionSource <object> allClosed = null;

                try
                {
                    TaskCompletionSource <object> shutdown = new TaskCompletionSource <object>();
                    using (CancellationTokenRegistration shutdownRegistration =
                               shutdownSignal.Register(() => { shutdown.SetResult(null); }))
                    {
                        Task[] tasks = new Task[2];
                        tasks[1] = shutdown.Task;
                        while (!shutdownSignal.IsCancellationRequested)
                        {
                            Task <TcpClient> acceptTask = this.listener.AcceptTcpClientAsync();
                            tasks[0] = acceptTask;
                            Task completedTask = await Task.WhenAny(tasks);

                            if (!object.ReferenceEquals(completedTask, acceptTask))
                            {
                                // Server shutdown
                                this.ConsumeException(acceptTask, "accept");
                                continue;
                            }
                            // New connection
                            TcpClient connection = acceptTask.Result;
                            lock (connectionCountLock)
                            {
                                Debug.Assert(openConnections >= 0);
                                openConnections++;
                            }
                            Task connectionTask = Task.Factory.StartNew(
                                async() =>
                            {
                                await this.ConnectionLoopAsync(connection, shutdownSignal);
                            },
                                shutdownSignal,
                                TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach,
                                TaskScheduler.Current);
                            var ignored = connectionTask.ContinueWith(t =>
                            {
                                TaskCompletionSource <object> done = null;
                                lock (connectionCountLock)
                                {
                                    Debug.Assert(openConnections > 0);
                                    openConnections--;
                                    if (openConnections == 0 && allClosed != null)
                                    {
                                        done = allClosed;
                                    }
                                }
                                if (done != null)
                                {
                                    done.SetResult(null);
                                }
                            });
                        }
                    }
                }
                finally
                {
                    Task done = null;
                    lock (connectionCountLock)
                    {
                        Debug.Assert(openConnections >= 0);
                        if (openConnections != 0)
                        {
                            Debug.Assert(allClosed == null);
                            allClosed = new TaskCompletionSource <object>();
                            done      = allClosed.Task;
                        }
                    }
                    if (done != null)
                    {
                        await done;
                    }
                }
            }
예제 #7
0
            public override async ValueTask <int> ReadAsync(Memory <byte> destination, CancellationToken cancellationToken)
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (_connection == null || destination.Length == 0)
                {
                    // Response body fully consumed or the caller didn't ask for any data
                    return(0);
                }

                Debug.Assert(_contentBytesRemaining > 0);

                if ((ulong)destination.Length > _contentBytesRemaining)
                {
                    destination = destination.Slice(0, (int)_contentBytesRemaining);
                }

                ValueTask <int> readTask = _connection.ReadAsync(destination);
                int             bytesRead;

                if (readTask.IsCompletedSuccessfully)
                {
                    bytesRead = readTask.Result;
                }
                else
                {
                    CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken);
                    try
                    {
                        bytesRead = await readTask.ConfigureAwait(false);
                    }
                    catch (Exception exc) when(ShouldWrapInOperationCanceledException(exc, cancellationToken))
                    {
                        throw CreateOperationCanceledException(exc, cancellationToken);
                    }
                    finally
                    {
                        ctr.Dispose();
                    }
                }

                if (bytesRead <= 0)
                {
                    // A cancellation request may have caused the EOF.
                    cancellationToken.ThrowIfCancellationRequested();

                    // Unexpected end of response stream.
                    throw new IOException(SR.net_http_invalid_response);
                }

                Debug.Assert((ulong)bytesRead <= _contentBytesRemaining);
                _contentBytesRemaining -= (ulong)bytesRead;

                if (_contentBytesRemaining == 0)
                {
                    // End of response body
                    _connection.CompleteResponse();
                    _connection = null;
                }

                return(bytesRead);
            }
        public static async Task <ProcessResult> RunAsTaskAsync(this ProcessStartInfo psi, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var logs = new List <ProcessOutput>();
            int exitCode;

            using (var process = new Process())
            {
                process.StartInfo = psi;
                if (psi.RedirectStandardError)
                {
                    process.ErrorDataReceived += (sender, e) =>
                    {
                        if (e.Data != null)
                        {
                            lock (logs)
                            {
                                logs.Add(new ProcessOutput(ProcessOutputType.StandardError, e.Data));
                            }
                        }
                    };
                }

                if (psi.RedirectStandardOutput)
                {
                    process.OutputDataReceived += (sender, e) =>
                    {
                        if (e.Data != null)
                        {
                            lock (logs)
                            {
                                logs.Add(new ProcessOutput(ProcessOutputType.StandardOutput, e.Data));
                            }
                        }
                    };
                }

                if (!process.Start())
                {
                    throw new Win32Exception("Cannot start the process");
                }

                if (psi.RedirectStandardError)
                {
                    process.BeginErrorReadLine();
                }

                if (psi.RedirectStandardOutput)
                {
                    process.BeginOutputReadLine();
                }

                if (psi.RedirectStandardInput)
                {
                    process.StandardInput.Close();
                }

                CancellationTokenRegistration registration = default;
                try
                {
                    if (cancellationToken.CanBeCanceled && !process.HasExited)
                    {
                        registration = cancellationToken.Register(() =>
                        {
                            try
                            {
                                process.Kill(entireProcessTree: true);
                            }
                            catch (InvalidOperationException)
                            {
                                try
                                {
                                    // Try to at least kill the root process
                                    process.Kill();
                                }
                                catch (InvalidOperationException)
                                {
                                }
                            }
                        });
                    }

                    await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false);

                    process.WaitForExit(); // https://github.com/dotnet/runtime/issues/42556
                }
                finally
                {
                    await registration.DisposeAsync().ConfigureAwait(false);
                }

                exitCode = process.ExitCode;
            }

            cancellationToken.ThrowIfCancellationRequested();
            return(new ProcessResult(exitCode, logs));
        }
예제 #9
0
 protected TestBase(ITestOutputHelper logger)
 {
     this.Logger                    = WriteTestOutputToFile ? new FileLogger($@"d:\temp\test.{DateTime.Now:HH-mm-ss.ff}.log", logger) : logger;
     this.timeoutTokenSource        = new CancellationTokenSource(TestTimeout);
     this.timeoutLoggerRegistration = this.timeoutTokenSource.Token.Register(() => logger.WriteLine("**Timeout token signaled** (Time index: {0:HH:mm:ss.ff}, Elapsed: {1})", DateTime.Now, this.ElapsedTime));
 }
예제 #10
0
 /// <summary>
 /// Initializes a new instance of the <see cref="DisposableBag"/> class.
 /// </summary>
 internal DisposableBag(CancellationToken cancellationToken = default)
 {
     _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
     _cancellationToken       = _cts.Token;
     _autoDisposeRegistration = RegisterNoThrowOnDispose(Dispose, cancellationToken);
 }
 public WorkPool(IModel model)
 {
     _actions           = new ConcurrentQueue <Action>();
     _tokenSource       = new CancellationTokenSource();
     _tokenRegistration = _tokenSource.Token.Register(() => _syncSource.TrySetCanceled());
 }
예제 #12
0
            private async ValueTask <int> ReadAsyncCore(Memory <byte> destination, CancellationToken cancellationToken)
            {
                // Should only be called if ReadChunksFromConnectionBuffer returned 0.

                Debug.Assert(_connection != null);
                Debug.Assert(destination.Length > 0);

                CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken);

                try
                {
                    while (true)
                    {
                        if (_connection == null)
                        {
                            // Fully consumed the response in ReadChunksFromConnectionBuffer.
                            return(0);
                        }

                        if (_state == ParsingState.ExpectChunkData &&
                            destination.Length >= _connection.ReadBufferSize &&
                            _chunkBytesRemaining >= (ulong)_connection.ReadBufferSize)
                        {
                            // As an optimization, we skip going through the connection's read buffer if both
                            // the remaining chunk data and the destination buffer are both at least as large
                            // as the connection buffer.  That avoids an unnecessary copy while still reading
                            // the maximum amount we'd otherwise read at a time.
                            Debug.Assert(_connection.RemainingBuffer.Length == 0);
                            int bytesRead = await _connection.ReadAsync(destination.Slice(0, (int)Math.Min((ulong)destination.Length, _chunkBytesRemaining)));

                            if (bytesRead == 0)
                            {
                                throw new IOException(SR.net_http_invalid_response);
                            }
                            _chunkBytesRemaining -= (ulong)bytesRead;
                            if (_chunkBytesRemaining == 0)
                            {
                                _state = ParsingState.ExpectChunkTerminator;
                            }
                            return(bytesRead);
                        }

                        // We're only here if we need more data to make forward progress.
                        await _connection.FillAsync();

                        // Now that we have more, see if we can get any response data, and if
                        // we can we're done.
                        int bytesCopied = ReadChunksFromConnectionBuffer(destination.Span);
                        if (bytesCopied > 0)
                        {
                            return(bytesCopied);
                        }
                    }
                }
                catch (Exception exc) when(ShouldWrapInOperationCanceledException(exc, cancellationToken))
                {
                    throw new OperationCanceledException(s_cancellationMessage, exc, cancellationToken);
                }
                finally
                {
                    ctr.Dispose();
                }
            }
예제 #13
0
 protected ScheduledAsyncTask(AbstractScheduledEventExecutor executor, long deadlineNanos, long periodNanos, IPromise promise, CancellationToken cancellationToken)
     : base(executor, deadlineNanos, periodNanos, promise)
 {
     _cancellationToken             = cancellationToken;
     _cancellationTokenRegistration = cancellationToken.Register(s => ((ScheduledAsyncTask)s).Cancel(), this);
 }
            private ReadOnlyMemory <byte> ReadChunkFromConnectionBuffer(int maxBytesToRead, CancellationTokenRegistration cancellationRegistration)
            {
                Debug.Assert(maxBytesToRead > 0);

                try
                {
                    ReadOnlySpan <byte> currentLine;
                    switch (_state)
                    {
                    case ParsingState.ExpectChunkHeader:
                        Debug.Assert(_chunkBytesRemaining == 0, $"Expected {nameof(_chunkBytesRemaining)} == 0, got {_chunkBytesRemaining}");

                        // Read the chunk header line.
                        _connection._allowedReadLineBytes = MaxChunkBytesAllowed;
                        if (!_connection.TryReadNextLine(out currentLine))
                        {
                            // Could not get a whole line, so we can't parse the chunk header.
                            return(default);
                        }

                        // Parse the hex value from it.
                        if (!Utf8Parser.TryParse(currentLine, out ulong chunkSize, out int bytesConsumed, 'X'))
                        {
                            throw new IOException(SR.net_http_invalid_response);
                        }
                        _chunkBytesRemaining = chunkSize;

                        // If there's a chunk extension after the chunk size, validate it.
                        if (bytesConsumed != currentLine.Length)
                        {
                            ValidateChunkExtension(currentLine.Slice(bytesConsumed));
                        }

                        // Proceed to handle the chunk.  If there's data in it, go read it.
                        // Otherwise, finish handling the response.
                        if (chunkSize > 0)
                        {
                            _state = ParsingState.ExpectChunkData;
                            goto case ParsingState.ExpectChunkData;
                        }
                        else
                        {
                            _state = ParsingState.ConsumeTrailers;
                            goto case ParsingState.ConsumeTrailers;
                        }

                    case ParsingState.ExpectChunkData:
                        Debug.Assert(_chunkBytesRemaining > 0);

                        ReadOnlyMemory <byte> connectionBuffer = _connection.RemainingBuffer;
                        if (connectionBuffer.Length == 0)
                        {
                            return(default);
예제 #15
0
 public CancelableEnumerator(IAsyncEnumerator <T> asyncEnumerator, CancellationTokenRegistration registration)
 {
     _asyncEnumerator = asyncEnumerator;
     _cancellationTokenRegistration = registration;
 }
예제 #16
0
        internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback, byte[] buffer, int offset, uint dataAlreadyRead, CancellationTokenRegistration cancellationRegistration)
            : this(requestStream, userState, callback)
        {
            _dataAlreadyRead = dataAlreadyRead;
            var boundHandle = requestStream.RequestContext.Server.RequestQueue.BoundHandle;

            _overlapped = new SafeNativeOverlapped(boundHandle,
                                                   boundHandle.AllocateNativeOverlapped(IOCallback, this, buffer));
            _pinnedBuffer             = (Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset));
            _cancellationRegistration = cancellationRegistration;
        }
 public CancellationEvent(CancellationToken cancellationToken)
 {
     _mre          = new ManualResetEvent(false);
     _registration = cancellationToken.Register(SetEvent, _mre);
 }
예제 #18
0
 private void UnregisterCancellationToken()
 {
     _cancellationTokenRegistration.Dispose();
     _cancellationTokenRegistration = default(CancellationTokenRegistration);
 }
 public DiposeCancellationState(CancellationCallbackWrapper callbackWrapper, CancellationTokenRegistration registration)
 {
     _callbackWrapper = callbackWrapper;
     _registration    = registration;
 }
예제 #20
0
 public WasmFetchResponse(JSObject fetchResponse, JSObject abortController, CancellationTokenRegistration abortRegistration)
 {
     this.fetchResponse     = fetchResponse;
     this.abortController   = abortController;
     this.abortRegistration = abortRegistration;
 }
예제 #21
0
 internal FollowCancelableTaskState <T> WithRegisteredCallback(CancellationTokenRegistration registeredCallback)
 => new FollowCancelableTaskState <T>(this.getTaskToFollow, registeredCallback, this.UltimateCancellation);
예제 #22
0
        private async Task doFetch(TaskCompletionSource <HttpResponseMessage> tcs, HttpRequestMessage request, CancellationToken cancellationToken)
        {
            try {
                var requestObject = new JSObject();
                requestObject.SetObjectProperty("method", request.Method.Method);

                // See https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials for
                // standard values and meanings
                requestObject.SetObjectProperty("credentials", DefaultCredentials);

                // See https://developer.mozilla.org/en-US/docs/Web/API/Request/cache for
                // standard values and meanings
                requestObject.SetObjectProperty("cache", Cache);

                // See https://developer.mozilla.org/en-US/docs/Web/API/Request/mode for
                // standard values and meanings
                requestObject.SetObjectProperty("mode", Mode);

                // We need to check for body content
                if (request.Content != null)
                {
                    if (request.Content is StringContent)
                    {
                        requestObject.SetObjectProperty("body", await request.Content.ReadAsStringAsync());
                    }
                    else
                    {
                        // 2.1.801 seems to have a problem with the line
                        // using (var uint8Buffer = Uint8Array.From(await request.Content.ReadAsByteArrayAsync ()))
                        // so we split it up into two lines.
                        var byteAsync = await request.Content.ReadAsByteArrayAsync();

                        using (var uint8Buffer = Uint8Array.From(byteAsync))
                        {
                            requestObject.SetObjectProperty("body", uint8Buffer);
                        }
                    }
                }

                // Process headers
                // Cors has it's own restrictions on headers.
                // https://developer.mozilla.org/en-US/docs/Web/API/Headers
                using (var jsHeaders = new HostObject("Headers")) {
                    if (request.Headers != null)
                    {
                        foreach (var header in request.Headers)
                        {
                            foreach (var value in header.Value)
                            {
                                jsHeaders.Invoke("append", header.Key, value);
                            }
                        }
                    }
                    if (request.Content?.Headers != null)
                    {
                        foreach (var header in request.Content.Headers)
                        {
                            foreach (var value in header.Value)
                            {
                                jsHeaders.Invoke("append", header.Key, value);
                            }
                        }
                    }
                    requestObject.SetObjectProperty("headers", jsHeaders);
                }

                JSObject           abortController    = null;
                JSObject           signal             = null;
                WasmHttpReadStream wasmHttpReadStream = null;

                CancellationTokenRegistration abortRegistration = default(CancellationTokenRegistration);
                if (cancellationToken.CanBeCanceled)
                {
                    abortController = new HostObject("AbortController");

                    signal = (JSObject)abortController.GetObjectProperty("signal");
                    requestObject.SetObjectProperty("signal", signal);
                    abortRegistration = cancellationToken.Register((Action)(() => {
                        if (abortController.JSHandle != -1)
                        {
                            abortController.Invoke((string)"abort");
                            abortController?.Dispose();
                        }
                        wasmHttpReadStream?.Dispose();
                    }));
                }

                var args = new Core.Array();
                args.Push(request.RequestUri.ToString());
                args.Push(requestObject);

                requestObject.Dispose();

                var response = fetch.Invoke("apply", window, args) as Task <object>;
                args.Dispose();
                if (response == null)
                {
                    throw new Exception("Internal error marshalling the response Promise from `fetch`.");
                }

                var t = await response;

                var status = new WasmFetchResponse((JSObject)t, abortController, abortRegistration);

                //Console.WriteLine($"bodyUsed: {status.IsBodyUsed}");
                //Console.WriteLine($"ok: {status.IsOK}");
                //Console.WriteLine($"redirected: {status.IsRedirected}");
                //Console.WriteLine($"status: {status.Status}");
                //Console.WriteLine($"statusText: {status.StatusText}");
                //Console.WriteLine($"type: {status.ResponseType}");
                //Console.WriteLine($"url: {status.Url}");

                HttpResponseMessage httpresponse = new HttpResponseMessage((HttpStatusCode)Enum.Parse(typeof(HttpStatusCode), status.Status.ToString()));

                httpresponse.Content = StreamingSupported && StreamingEnabled
                                    ? new StreamContent(wasmHttpReadStream = new WasmHttpReadStream(status))
                                    : (HttpContent) new WasmHttpContent(status);

                // Fill the response headers
                // CORS will only allow access to certain headers.
                // If a request is made for a resource on another origin which returns the CORs headers, then the type is cors.
                // cors and basic responses are almost identical except that a cors response restricts the headers you can view to
                // `Cache-Control`, `Content-Language`, `Content-Type`, `Expires`, `Last-Modified`, and `Pragma`.
                // View more information https://developers.google.com/web/updates/2015/03/introduction-to-fetch#response_types
                //
                // Note: Some of the headers may not even be valid header types in .NET thus we use TryAddWithoutValidation
                using (var respHeaders = (JSObject)status.Headers) {
                    if (respHeaders != null)
                    {
                        using (var entriesIterator = (JSObject)respHeaders.Invoke("entries")) {
                            JSObject nextResult = null;
                            try {
                                nextResult = (JSObject)entriesIterator.Invoke("next");
                                while (!(bool)nextResult.GetObjectProperty("done"))
                                {
                                    using (var resultValue = (WebAssembly.Core.Array)nextResult.GetObjectProperty("value")) {
                                        var name  = (string)resultValue [0];
                                        var value = (string)resultValue [1];
                                        if (!httpresponse.Headers.TryAddWithoutValidation(name, value))
                                        {
                                            if (httpresponse.Content != null)
                                            {
                                                if (!httpresponse.Content.Headers.TryAddWithoutValidation(name, value))
                                                {
                                                    Console.WriteLine($"Warning: Can not add response header for name: {name} value: {value}");
                                                }
                                            }
                                        }
                                    }
                                    nextResult?.Dispose();
                                    nextResult = (JSObject)entriesIterator.Invoke("next");
                                }
                            } finally {
                                nextResult?.Dispose();
                            }
                        }
                    }
                }

                tcs.SetResult(httpresponse);

                signal?.Dispose();
            } catch (Exception exception) {
                tcs.SetException(exception);
            }
        }
        /// <summary>
        /// Returns a task that will receive the last value or the exception produced by the observable sequence.
        /// </summary>
        /// <typeparam name="TResult">The type of the elements in the source sequence.</typeparam>
        /// <param name="observable">Observable sequence to convert to a task.</param>
        /// <param name="cancellationToken">Cancellation token that can be used to cancel the task, causing unsubscription from the observable sequence.</param>
        /// <param name="state">The state to use as the underlying task's AsyncState.</param>
        /// <returns>A task that will receive the last element or the exception produced by the observable sequence.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="observable"/> is null.</exception>
        public static Task <TResult> ToTask <TResult>(this IObservable <TResult> observable, CancellationToken cancellationToken, object state)
        {
            if (observable == null)
            {
                throw new ArgumentNullException("observable");
            }

            bool    hasValue  = false;
            TResult lastValue = default(TResult);

            TaskCompletionSource <TResult> tcs = new TaskCompletionSource <TResult>(state);

            SingleAssignmentDisposable disposable = new SingleAssignmentDisposable();

            CancellationTokenRegistration ctr = default(CancellationTokenRegistration);

            if (cancellationToken.CanBeCanceled)
            {
                ctr = cancellationToken.Register(() =>
                {
                    disposable.Dispose();
                    tcs.TrySetCanceled(cancellationToken);
                });
            }

            IObserver <TResult> taskCompletionObserver = Observer.Create <TResult>(
                value =>
            {
                hasValue  = true;
                lastValue = value;
            },
                ex =>
            {
                tcs.TrySetException(ex);

                ctr.Dispose();     // no null-check needed (struct)
                disposable.Dispose();
            },
                () =>
            {
                if (hasValue)
                {
                    tcs.TrySetResult(lastValue);
                }
                else
                {
                    tcs.TrySetException(new InvalidOperationException("Strings_Linq.NO_ELEMENTS"));
                }

                ctr.Dispose();     // no null-check needed (struct)
                disposable.Dispose();
            }
                );

            //
            // Subtle race condition: if the source completes before we reach the line below, the SingleAssigmentDisposable
            // will already have been disposed. Upon assignment, the disposable resource being set will be disposed on the
            // spot, which may throw an exception. (Similar to TFS 487142)
            //
            try
            {
                //
                // [OK] Use of unsafe Subscribe: we're catching the exception here to set the TaskCompletionSource.
                //
                // Notice we could use a safe subscription to route errors through OnError, but we still need the
                // exception handling logic here for the reason explained above. We cannot afford to throw here
                // and as a result never set the TaskCompletionSource, so we tunnel everything through here.
                //
                disposable.Disposable = observable.Subscribe/*Unsafe*/ (taskCompletionObserver);
            }
            catch (Exception ex)
            {
                tcs.TrySetException(ex);
            }

            return(tcs.Task);
        }
예제 #24
0
 protected TestBase(ITestOutputHelper logger)
 {
     this.Logger                    = logger;
     this.timeoutTokenSource        = new CancellationTokenSource(TestTimeout);
     this.timeoutLoggerRegistration = this.timeoutTokenSource.Token.Register(() => logger.WriteLine("**Timeout token signaled**"));
 }
예제 #25
0
        public Task SendMailAsync(MailMessage message, CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(Task.FromCanceled(cancellationToken));
            }

            // Create a TaskCompletionSource to represent the operation
            var tcs = new TaskCompletionSource();

            CancellationTokenRegistration ctr = default;

            // Indicates whether the CTR has been set - captured in handler
            int state = 0;

            // Register a handler that will transfer completion results to the TCS Task
            SendCompletedEventHandler?handler = null;

            handler = (sender, e) =>
            {
                if (e.UserState == tcs)
                {
                    try
                    {
                        ((SmtpClient)sender).SendCompleted -= handler;
                        if (Interlocked.Exchange(ref state, 1) != 0)
                        {
                            // A CTR has been set, we have to wait until it completes before completing the task
                            ctr.Dispose();
                        }
                    }
                    catch (ObjectDisposedException) { } // SendAsyncCancel will throw if SmtpClient was disposed
                    finally
                    {
                        if (e.Error != null)
                        {
                            tcs.TrySetException(e.Error);
                        }
                        else if (e.Cancelled)
                        {
                            tcs.TrySetCanceled();
                        }
                        else
                        {
                            tcs.TrySetResult();
                        }
                    }
                }
            };
            SendCompleted += handler;

            // Start the async operation.
            try
            {
                SendAsync(message, tcs);
            }
            catch
            {
                SendCompleted -= handler;
                throw;
            }

            ctr = cancellationToken.Register(s =>
            {
                ((SmtpClient)s !).SendAsyncCancel();
            }, this);

            if (Interlocked.Exchange(ref state, 1) != 0)
            {
                // SendCompleted was already invoked, ensure the CTR completes before returning the task
                ctr.Dispose();
            }

            // Return the task to represent the asynchronous operation
            return(tcs.Task);
        }
예제 #26
0
 internal static void TryDeregister(this CancellationTokenRegistration ctr)
 {
     //nothing to do for projectN
 }
예제 #27
0
 public WithCancellationSource(UniTask task, CancellationToken cancellationToken)
 {
     this.cancellationToken = cancellationToken;
     this.tokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallbackDelegate, this);
     RunTask(task).Forget();
 }
예제 #28
0
            private async ValueTask <int> ReadAsyncCore(Memory <byte> buffer, CancellationToken cancellationToken)
            {
                // Should only be called if ReadChunksFromConnectionBuffer returned 0.

                Debug.Assert(_connection != null);

                CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken);

                try
                {
                    while (true)
                    {
                        if (_connection == null)
                        {
                            // Fully consumed the response in ReadChunksFromConnectionBuffer.
                            return(0);
                        }

                        if (_state == ParsingState.ExpectChunkData &&
                            buffer.Length >= _connection.ReadBufferSize &&
                            _chunkBytesRemaining >= (ulong)_connection.ReadBufferSize)
                        {
                            // As an optimization, we skip going through the connection's read buffer if both
                            // the remaining chunk data and the buffer are both at least as large
                            // as the connection buffer.  That avoids an unnecessary copy while still reading
                            // the maximum amount we'd otherwise read at a time.
                            Debug.Assert(_connection.RemainingBuffer.Length == 0);
                            Debug.Assert(buffer.Length != 0);
                            int bytesRead = await _connection.ReadAsync(buffer.Slice(0, (int)Math.Min((ulong)buffer.Length, _chunkBytesRemaining))).ConfigureAwait(false);

                            if (bytesRead == 0)
                            {
                                throw new IOException(SR.Format(SR.net_http_invalid_response_premature_eof_bytecount, _chunkBytesRemaining));
                            }
                            _chunkBytesRemaining -= (ulong)bytesRead;
                            if (_chunkBytesRemaining == 0)
                            {
                                _state = ParsingState.ExpectChunkTerminator;
                            }
                            return(bytesRead);
                        }

                        if (buffer.Length == 0)
                        {
                            // User requested a zero-byte read, and we have no data available in the buffer for processing.
                            // This zero-byte read indicates their desire to trade off the extra cost of a zero-byte read
                            // for reduced memory consumption when data is not immediately available.
                            // So, we will issue our own zero-byte read against the underlying stream to allow it to make use of
                            // optimizations, such as deferring buffer allocation until data is actually available.
                            await _connection.ReadAsync(buffer).ConfigureAwait(false);
                        }

                        // We're only here if we need more data to make forward progress.
                        await _connection.FillAsync(async : true).ConfigureAwait(false);

                        // Now that we have more, see if we can get any response data, and if
                        // we can we're done.
                        if (buffer.Length == 0)
                        {
                            if (PeekChunkFromConnectionBuffer())
                            {
                                return(0);
                            }
                        }
                        else
                        {
                            int bytesCopied = ReadChunksFromConnectionBuffer(buffer.Span, ctr);
                            if (bytesCopied > 0)
                            {
                                return(bytesCopied);
                            }
                        }
                    }
                }
                catch (Exception exc) when(CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken))
                {
                    throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken);
                }
                finally
                {
                    ctr.Dispose();
                }
            }
예제 #29
0
        public override Task SendAsync(
            ArraySegment <byte> buffer,
            WebSocketMessageType messageType,
            bool endOfMessage,
            CancellationToken cancellationToken)
        {
            _operation.InterlockedCheckValidStates(s_validSendStates);

            using (CancellationTokenRegistration ctr = ThrowOrRegisterCancellation(cancellationToken))
            {
                var bufferType = WebSocketMessageTypeAdapter.GetWinHttpMessageType(messageType, endOfMessage);

                // TODO (Issue 2505): replace with PinnableBufferCache.
                if (!_cachedSendPinnedBuffer.IsAllocated || _cachedSendPinnedBuffer.Target != buffer.Array)
                {
                    if (_cachedSendPinnedBuffer.IsAllocated)
                    {
                        _cachedSendPinnedBuffer.Free();
                    }

                    _cachedSendPinnedBuffer = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned);
                }

                bool sendOperationAlreadyPending = false;
                if (_operation.PendingWriteOperation == false)
                {
                    lock (_operation.Lock)
                    {
                        _operation.CheckValidState(s_validSendStates);

                        if (_operation.PendingWriteOperation == false)
                        {
                            _operation.PendingWriteOperation = true;
                            _operation.TcsSend = new TaskCompletionSource <bool>();

                            uint ret = Interop.WinHttp.WinHttpWebSocketSend(
                                _operation.WebSocketHandle,
                                bufferType,
                                buffer.Count > 0 ? Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Array, buffer.Offset) : IntPtr.Zero,
                                (uint)buffer.Count);

                            if (Interop.WinHttp.ERROR_SUCCESS != ret)
                            {
                                throw WinHttpException.CreateExceptionUsingError((int)ret);
                            }
                        }
                        else
                        {
                            sendOperationAlreadyPending = true;
                        }
                    }
                }
                else
                {
                    sendOperationAlreadyPending = true;
                }

                if (sendOperationAlreadyPending)
                {
                    var exception = new InvalidOperationException(
                        SR.Format(SR.net_Websockets_AlreadyOneOutstandingOperation, "SendAsync"));

                    _operation.TcsSend.TrySetException(exception);
                    Abort();
                }

                return(_operation.TcsSend.Task);
            }
        }
 internal BackgroundCommandHandler(IFtpConnection connection)
 {
     _connection = connection;
     _cancellationTokenRegistration = _connection.CancellationToken.Register(() => _cancellationTokenSource.Cancel(true));
 }
예제 #31
0
        private async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken)
        {
            HttpWebResponse response = null;
            CancellationTokenRegistration connectCancellation = new CancellationTokenRegistration();

            // Any errors from here on out are fatal and this instance will be disposed.
            try
            {
                HttpWebRequest request = CreateAndConfigureRequest(uri);
                if (Logging.On)
                {
                    Logging.Associate(Logging.WebSockets, this, request);
                }

                connectCancellation = cancellationToken.Register(AbortRequest, request, false);

                response = await request.GetResponseAsync().SuppressContextFlow() as HttpWebResponse;

                Contract.Assert(response != null, "Not an HttpWebResponse");

                if (Logging.On)
                {
                    Logging.Associate(Logging.WebSockets, this, response);
                }

                this.ResponseHeaders = response.Headers;
                string subprotocol = ValidateResponse(request, response);

                innerWebSocket = WebSocket.CreateClientWebSocket(response.GetResponseStream(), subprotocol,
                                                                 options.ReceiveBufferSize, options.SendBufferSize, options.KeepAliveInterval, false,
                                                                 options.GetOrCreateBuffer());

                if (Logging.On)
                {
                    Logging.Associate(Logging.WebSockets, this, innerWebSocket);
                }

                // Change internal state to 'connected' to enable the other methods
                if (Interlocked.CompareExchange(ref state, connected, connecting) != connecting)
                {
                    // Aborted/Disposed during connect.
                    throw new ObjectDisposedException(GetType().FullName);
                }
            }
            catch (WebException ex)
            {
                ConnectExceptionCleanup(response);
                WebSocketException wex = new WebSocketException(SR.GetString(SR.net_webstatus_ConnectFailure), ex);
                if (Logging.On)
                {
                    Logging.Exception(Logging.WebSockets, this, "ConnectAsync", wex);
                }
                throw wex;
            }
            catch (Exception ex)
            {
                ConnectExceptionCleanup(response);
                if (Logging.On)
                {
                    Logging.Exception(Logging.WebSockets, this, "ConnectAsync", ex);
                }
                throw;
            }
            finally
            {
                // We successfully connected (or failed trying), disengage from this token.
                // Otherwise any timeout/cancellation would apply to the full session.
                // In the failure case we need to release the reference to HWR.
                connectCancellation.Dispose();
            }
        }
예제 #32
0
        private async ValueTask <FlushResult> FlushAsyncInternal(CancellationToken cancellationToken = default)
        {
            // Write all completed segments and whatever remains in the current segment
            // and flush the result.
            CancellationTokenRegistration reg = new CancellationTokenRegistration();

            if (cancellationToken.CanBeCanceled)
            {
                reg = cancellationToken.Register(state => ((StreamPipeWriter)state).Cancel(), this);
            }
            using (reg)
            {
                var localToken = InternalTokenSource.Token;
                try
                {
                    if (_completedSegments != null && _completedSegments.Count > 0)
                    {
                        var count = _completedSegments.Count;
                        for (var i = 0; i < count; i++)
                        {
                            var segment = _completedSegments[0];
#if NETCOREAPP3_0
                            await _writingStream.WriteAsync(segment.Buffer.Slice(0, segment.Length), localToken);
#elif NETSTANDARD2_0
                            MemoryMarshal.TryGetArray <byte>(segment.Buffer, out var arraySegment);
                            await _writingStream.WriteAsync(arraySegment.Array, 0, segment.Length, localToken);
#else
#error Target frameworks need to be updated.
#endif
                            _bytesWritten -= segment.Length;
                            segment.Return();
                            _completedSegments.RemoveAt(0);
                        }
                    }

                    if (!_currentSegment.IsEmpty)
                    {
#if NETCOREAPP3_0
                        await _writingStream.WriteAsync(_currentSegment.Slice(0, _position), localToken);
#elif NETSTANDARD2_0
                        MemoryMarshal.TryGetArray <byte>(_currentSegment, out var arraySegment);
                        await _writingStream.WriteAsync(arraySegment.Array, 0, _position, localToken);
#else
#error Target frameworks need to be updated.
#endif
                        _bytesWritten -= _position;
                        _position      = 0;
                    }

                    await _writingStream.FlushAsync(localToken);

                    return(new FlushResult(isCanceled: false, IsCompletedOrThrow()));
                }
                catch (OperationCanceledException)
                {
                    // Remove the cancellation token such that the next time Flush is called
                    // A new CTS is created.
                    lock (_lockObject)
                    {
                        _internalTokenSource = null;
                    }

                    if (cancellationToken.IsCancellationRequested)
                    {
                        throw;
                    }

                    // Catch any cancellation and translate it into setting isCanceled = true
                    return(new FlushResult(isCanceled: true, IsCompletedOrThrow()));
                }
            }
        }