private static void FormatRequestAndValidate(HttpRequestMessage request, string expected) { var buffer = new byte[8192]; var result = HttpFormatter.FormatRequest(request, buffer); var decodedString = Encoding.UTF8.GetString(buffer, 0, result); Assert.Equal(expected, decodedString); }
public async Task <HttpResponseMessage> SendRequest(HttpRequestMessage requestMessage, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (requestMessage.Headers.Contains(MazeHeaders.MazeSocketRequestIdHeader)) { throw new ArgumentException( $"The maze request must not have a {MazeHeaders.MazeSocketRequestIdHeader} header.", nameof(requestMessage)); } var requestId = Interlocked.Increment(ref _requestCounter); requestMessage.Headers.Add(MazeHeaders.MazeSocketRequestIdHeader, requestId.ToString()); var requestWaiter = new TaskCompletionSource <HttpResponseMessage>(); _waitingRequests.TryAdd(requestId, requestWaiter); using (var sendBuffer = AllocateBuffer(_packageBufferSize)) { var headerLength = HttpFormatter.FormatRequest(requestMessage, sendBuffer); var maxReadLength = sendBuffer.Length - headerLength; var opCode = MazeSocket.MessageOpcode.Request; Stream bodyStream; if (requestMessage.Content != null) { bodyStream = await requestMessage.Content.ReadAsStreamAsync(); } else { bodyStream = null; } using (bodyStream) { int read; if (bodyStream == null) //no body, single package, easy { opCode = MazeSocket.MessageOpcode.RequestSinglePackage; read = 0; } else { //read something var readOffset = sendBuffer.Offset + headerLength; read = await bodyStream.ReadAsync(sendBuffer.Buffer, readOffset, maxReadLength, cancellationToken); if (read < maxReadLength) { if (read == 0) { //no data in the stream opCode = MazeSocket.MessageOpcode.RequestSinglePackage; } else { //we read less than requested. check if we already reached the end readOffset += read; var read2 = await bodyStream.ReadAsync(sendBuffer.Buffer, readOffset, maxReadLength - read, cancellationToken); if (read2 == 0) { opCode = MazeSocket.MessageOpcode.RequestSinglePackage; } else { read += read2; } } } } cancellationToken .ThrowIfCancellationRequested(); //last chance without having to send a cancel package try { await _socket.SendFrameAsync(opCode, new ArraySegment <byte>(sendBuffer.Buffer, sendBuffer.Offset, read + headerLength), bufferHasRequiredLength : true, cancellationToken); if (opCode == MazeSocket.MessageOpcode.Request) { BinaryUtils.WriteInt32(sendBuffer.Buffer, sendBuffer.Offset, requestId); opCode = MazeSocket.MessageOpcode.RequestContinuation; maxReadLength = sendBuffer.Length - 4; while (true) { var readOffset = sendBuffer.Offset + 4; //4 for the request id read = await bodyStream.ReadAsync(sendBuffer.Buffer, readOffset, maxReadLength, cancellationToken); if (read == 0) { opCode = MazeSocket.MessageOpcode.RequestContinuationFinished; } else if (read < maxReadLength) { var read2 = await bodyStream.ReadAsync(sendBuffer.Buffer, readOffset + read, maxReadLength - read, cancellationToken); if (read2 == 0) { opCode = MazeSocket.MessageOpcode.RequestContinuationFinished; } else { read += read2; } } await _socket.SendFrameAsync(opCode, new ArraySegment <byte>(sendBuffer.Buffer, sendBuffer.Offset, 4 + read), bufferHasRequiredLength : true, cancellationToken); if (opCode == MazeSocket.MessageOpcode.RequestContinuationFinished) { break; } } } } catch (Exception) { BinaryUtils.WriteInt32(sendBuffer.Buffer, sendBuffer.Offset, requestId); await _socket.SendFrameAsync(MazeSocket.MessageOpcode.CancelRequest, new ArraySegment <byte>(sendBuffer.Buffer, sendBuffer.Offset, 4), bufferHasRequiredLength : true, CancellationToken.None); //DO NOT USE THE CANCELLATION TOKEN HERE throw; } } cancellationToken.Register(() => { using (var buffer = AllocateBuffer(4)) { BinaryUtils.WriteInt32(buffer.Buffer, buffer.Offset, requestId); _socket.SendFrameAsync(MazeSocket.MessageOpcode.CancelRequest, new ArraySegment <byte>(buffer.Buffer, buffer.Offset, 4), bufferHasRequiredLength: true, CancellationToken.None).Wait(); } requestWaiter.TrySetCanceled(); }); return(await requestWaiter.Task); } }