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; } }