| | | 1 | | // Licensed to the .NET Foundation under one or more agreements. |
| | | 2 | | // The .NET Foundation licenses this file to you under the MIT license. |
| | | 3 | | |
| | | 4 | | using System; |
| | | 5 | | using System.Buffers; |
| | | 6 | | using System.Diagnostics; |
| | | 7 | | using System.Threading.Tasks; |
| | | 8 | | using CoreWCF.Configuration; |
| | | 9 | | using CoreWCF.Runtime; |
| | | 10 | | |
| | | 11 | | namespace CoreWCF.Channels.Framing |
| | | 12 | | { |
| | | 13 | | internal class DuplexFramingMiddleware |
| | | 14 | | { |
| | | 15 | | private readonly HandshakeDelegate _next; |
| | | 16 | | |
| | 83 | 17 | | public DuplexFramingMiddleware(HandshakeDelegate next) |
| | | 18 | | { |
| | 83 | 19 | | _next = next; |
| | 83 | 20 | | } |
| | | 21 | | |
| | | 22 | | public async Task OnConnectedAsync(FramingConnection connection) |
| | | 23 | | { |
| | 65 | 24 | | var decoder = new ServerSessionDecoder(ConnectionOrientedTransportDefaults.MaxViaSize, ConnectionOrientedTra |
| | 65 | 25 | | bool success = false; |
| | | 26 | | |
| | | 27 | | try |
| | | 28 | | { |
| | | 29 | | ReadOnlySequence<byte> buffer; |
| | 130 | 30 | | while (decoder.CurrentState != ServerSessionDecoder.State.PreUpgradeStart) |
| | | 31 | | { |
| | 65 | 32 | | System.IO.Pipelines.ReadResult readResult = await connection.Input.ReadAsync(connection.ChannelIniti |
| | 65 | 33 | | buffer = readResult.Buffer; |
| | | 34 | | |
| | 65 | 35 | | if (readResult.IsCompleted && buffer.IsEmpty) |
| | | 36 | | { |
| | | 37 | | // The peer closed the connection before sending the via record. Surface |
| | | 38 | | // this as a premature EOF; otherwise PipeReader.ReadAsync would keep |
| | | 39 | | // returning synchronously with an empty buffer and the outer loop would |
| | | 40 | | // never make progress. |
| | 0 | 41 | | throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(decoder.CreatePrematureEOFException()) |
| | | 42 | | } |
| | | 43 | | |
| | 329 | 44 | | while (buffer.Length > 0) |
| | | 45 | | { |
| | 329 | 46 | | int bytesDecoded = decoder.Decode(buffer); |
| | 329 | 47 | | if (bytesDecoded > 0) |
| | | 48 | | { |
| | 329 | 49 | | buffer = buffer.Slice(bytesDecoded); |
| | | 50 | | } |
| | | 51 | | |
| | 329 | 52 | | if (decoder.CurrentState == ServerSessionDecoder.State.PreUpgradeStart) |
| | | 53 | | { |
| | | 54 | | // We now know the Via address (which endpoint the client is connecting to). |
| | | 55 | | // The connection now needs to be handled by the correct endpoint which can |
| | | 56 | | // handle upgrades etc. |
| | | 57 | | break; //exit loop |
| | | 58 | | } |
| | | 59 | | } |
| | | 60 | | |
| | 65 | 61 | | connection.Input.AdvanceTo(buffer.Start); |
| | | 62 | | } |
| | | 63 | | |
| | 65 | 64 | | success = true; |
| | 65 | 65 | | } |
| | | 66 | | catch (CommunicationException exception) |
| | | 67 | | { |
| | 0 | 68 | | DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information); |
| | 0 | 69 | | } |
| | | 70 | | catch (OperationCanceledException exception) |
| | | 71 | | { |
| | | 72 | | //if (TD.ReceiveTimeoutIsEnabled()) |
| | | 73 | | //{ |
| | | 74 | | // TD.ReceiveTimeout(exception.Message); |
| | | 75 | | //} |
| | 0 | 76 | | DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information); |
| | 0 | 77 | | } |
| | | 78 | | catch (TimeoutException exception) |
| | | 79 | | { |
| | | 80 | | //if (TD.ReceiveTimeoutIsEnabled()) |
| | | 81 | | //{ |
| | | 82 | | // TD.ReceiveTimeout(exception.Message); |
| | | 83 | | //} |
| | 0 | 84 | | DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information); |
| | 0 | 85 | | } |
| | | 86 | | catch (Exception e) |
| | | 87 | | { |
| | 0 | 88 | | if (Fx.IsFatal(e)) |
| | | 89 | | { |
| | 0 | 90 | | throw; |
| | | 91 | | } |
| | 0 | 92 | | if (!TransportExceptionHandler.HandleTransportExceptionHelper(e)) |
| | | 93 | | { |
| | 0 | 94 | | throw; |
| | | 95 | | } |
| | | 96 | | // containment -- all exceptions abort the reader, no additional containment action necessary |
| | 0 | 97 | | } |
| | | 98 | | finally |
| | | 99 | | { |
| | 65 | 100 | | if (!success) |
| | | 101 | | { |
| | | 102 | | // TODO: On .NET Framework, this Abort call via a long winding path of plumbing will trigger a new p |
| | | 103 | | // as this connection establishment handshake has failed. Some back pressure mechanism needs to be i |
| | | 104 | | // stop extra incoming connection handshakes from being started. Maybe a semaphore which is async wa |
| | | 105 | | // incoming request and then released on completion of handshake or on an exception. It also closes |
| | | 106 | | // so that's all that's happening here for now. Returning and completing the task will cause the con |
| | 0 | 107 | | connection.Abort(); |
| | | 108 | | } |
| | | 109 | | } |
| | | 110 | | |
| | 65 | 111 | | if (success) |
| | | 112 | | { |
| | 65 | 113 | | connection.FramingDecoder = decoder; |
| | 65 | 114 | | await _next(connection); |
| | | 115 | | } |
| | | 116 | | // else: |
| | | 117 | | // returning will close the connection if it hasn't already been. |
| | 64 | 118 | | } |
| | | 119 | | } |
| | | 120 | | } |