Example #1
0
        private async Task CreateServerStreamAndListen(int threadNumber, Action <Stream> onConnection,
                                                       CancellationToken cancelToken)
        {
            try
            {
                while (!cancelToken.IsCancellationRequested)
                {
                    var serverStream = new NamedPipeServerStream(_pipeName, PipeDirection.InOut, _maxAllowedServerInstances, _pipeTransmissionMode, _pipeOptions);
                    try
                    {
                        _logger.LogVerbose("[ thread " + threadNumber + "] Waiting for connection..");
                        await serverStream.WaitForConnectionAsync(cancelToken).ConfigureAwait(false);

                        _logger.LogVerbose("[ thread " + threadNumber + "] Found connection!");
                        // MP: We deliberately don't await this because we want to kick off the work on a background thead
                        // and immediately check for the next client connecting
#pragma warning disable CS4014                         // Because this call is not awaited, execution of the current method continues before the call is completed
                        Task.Run(() => onConnection(serverStream), cancelToken);
#pragma warning restore CS4014                         // Because this call is not awaited, execution of the current method continues before the call is completed
                    }
                    catch (OperationCanceledException) // Thrown when cancellationToken is cancelled
                    {
                        _logger.LogVerbose("[ thread " + threadNumber + "] Cancelling server wait.");
                        serverStream.Dispose();
                    }
                    catch (IOException ex) // Thrown if client disconnects early
                    {
                        if (ex.Message.Contains("The pipe is being closed."))
                        {
                            _logger.LogVerbose("[ thread " + threadNumber + "] IOException: Could not read Named Pipe message - client disconnected before server finished reading.");
                        }
                        else
                        {
                            _logger.LogWarning("[ thread " + threadNumber + "] IOException, possibly because the client disconnected early:" + ex);
                        }
                        serverStream.Dispose();
                    }
                    catch (Exception e)
                    {
                        _logger.LogError("[ thread " + threadNumber + "] Exception thrown during server stream wait:" + e);
                        serverStream.Dispose();
                    }
                }
                _logger.LogVerbose("[ thread " + threadNumber + "] Stopping thread - cancelled");
            }
            catch (Exception e)
            {
                _logger.LogError("[ thread " + threadNumber + "] Exception creating server stream:" + e);
            }
        }
        protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            ValidateAndNormalizeRequest(request);
            Stream stream = null;

            try
            {
                _logger.LogVerbose("HttpOS Client: Trying to connect..");
                stream = await _dial.DialAsync(request, cancellationToken).ConfigureAwait(false);

                _logger.LogVerbose("HttpOS Client: Connected.");
                request.Properties.Add(UnderlyingStreamProperty, stream);

                _logger.LogVerbose("HttpOS Client: Writing request");
                await stream.WriteClientMethodAndHeadersAsync(request, cancellationToken).ConfigureAwait(false);

                // as soon as headers are sent, we should begin reading the response, and send the request body concurrently
                // This is because if the server 404s nothing will ever read the response and it'll hang waiting
                // for someone to read it
                var writeContentTask = Task.Run(async() =>  // Cancel this task if server response detected
                {
                    if (request.Content != null)
                    {
                        _logger.LogVerbose("HttpOS Client: Writing request request.Content.CopyToAsync");
                        await request.Content.CopyToAsync(stream).ConfigureAwait(false);
                    }

                    _logger.LogVerbose("HttpOS Client:  stream.FlushAsync");
                    await stream.FlushAsync(cancellationToken).ConfigureAwait(false);
                    _logger.LogVerbose("HttpOS Client: Finished writing request");
                }, cancellationToken);

                var responseContent = new DialResponseContent();
                var response        = new HttpResponseMessage {
                    RequestMessage = request, Content = responseContent
                };

                _logger.LogVerbose("HttpOS Client: Waiting for response");
                string statusLine = await stream.ReadLineAsync(cancellationToken).ConfigureAwait(false);

                _logger.LogVerbose("HttpOS Client: Read 1st response line");
                ParseStatusLine(response, statusLine);
                _logger.LogVerbose("HttpOS Client: ParseStatusLine");
                for (;;)
                {
                    var line = await stream.ReadLineAsync(cancellationToken).ConfigureAwait(false);

                    if (line.Length == 0)
                    {
                        _logger.LogVerbose("HttpOS Client: Found empty line, end of response headers");
                        break;
                    }

                    try
                    {
                        _logger.LogVerbose("HttpOS Client: Parsing line:" + line);
                        (var name, var value) = HttpParser.ParseHeaderNameValues(line);
                        if (!response.Headers.TryAddWithoutValidation(name, value))
                        {
                            response.Content.Headers.TryAddWithoutValidation(name, value);
                        }
                    }
                    catch (FormatException ex)
                    {
                        throw new HttpRequestException("Error parsing header", ex);
                    }
                }

                _logger.LogVerbose("HttpOS Client: Finished reading response header lines");
                responseContent.SetContent(
                    new BodyStream(stream, response.Content.Headers.ContentLength, closeOnReachEnd: true),
                    response.Content.Headers.ContentLength);
                return(response);
            }
            catch (TimeoutException)
            {
                _logger.LogWarning("HttpOS Client: connection timed out.");
                stream?.Dispose();
                throw;
            }
            catch (Exception e)
            {
                _logger.LogError("HttpOS Client: Exception:" + e.Message);
                stream?.Dispose();
                throw;
            }
        }