// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { [Collection(IISTestSiteCollection.Name)] public class SynchronousReadAndWriteTests: FixtureLoggedTest { private readonly IISTestSiteFixture _fixture; public SynchronousReadAndWriteTests(IISTestSiteFixture fixture): base(fixture) { _fixture = fixture; } [ConditionalFact] public async Task ReadAndWriteSynchronously() { for (int i = 0; i < 100; i++) { var content = new StringContent(new string('a', 100000)); var response = await _fixture.Client.PostAsync("ReadAndWriteSynchronously", content); var responseText = await response.Content.ReadAsStringAsync(); Assert.Equal(expected: 110000, actual: responseText.Length); } } [ConditionalFact] public async Task ReadAndWriteEcho() { var body = new string('a', 100000); var content = new StringContent(body); var response = await _fixture.Client.PostAsync("ReadAndWriteEcho", content); var responseText = await response.Content.ReadAsStringAsync(); Assert.Equal(body, responseText); } [ConditionalFact] public async Task ReadAndWriteCopyToAsync() { var body = new string('a', 100000); var content = new StringContent(body); var response = await _fixture.Client.PostAsync("ReadAndWriteCopyToAsync", content); var responseText = await response.Content.ReadAsStringAsync(); Assert.Equal(body, responseText); } [ConditionalFact] public async Task ReadAndWriteEchoTwice() { var requestBody = new string('a', 10000); var content = new StringContent(requestBody); var response = await _fixture.Client.PostAsync("ReadAndWriteEchoTwice", content); var responseText = await response.Content.ReadAsStringAsync(); Assert.Equal(requestBody.Length * 2, responseText.Length); } [ConditionalFact] public async Task ReadSetHeaderWrite() { var body = "Body text"; var content = new StringContent(body); var response = await _fixture.Client.PostAsync("SetHeaderFromBody", content); var responseText = await response.Content.ReadAsStringAsync(); Assert.Equal(body, response.Headers.GetValues("BodyAsString").Single()); Assert.Equal(body, responseText); } [ConditionalFact] public async Task ReadAndWriteSlowConnection() { using (var connection = _fixture.CreateTestConnection()) { var testString = "hello world"; var request = $"POST /ReadAndWriteSlowConnection HTTP/1.0\r\n" + $"Content-Length: {testString.Length}\r\n" + "Host: " + "localhost\r\n" + "\r\n" + testString; foreach (var c in request) { await connection.Send(c.ToString()); await Task.Delay(10); } await connection.Receive( "HTTP/1.1 200 OK", ""); await connection.ReceiveHeaders(); for (int i = 0; i < 100; i++) { foreach (var c in testString) { await connection.Receive(c.ToString()); } await Task.Delay(10); } await connection.WaitForConnectionClose(); } } [ConditionalFact] public async Task ReadAndWriteInterleaved() { using (var connection = _fixture.CreateTestConnection()) { var requestLength = 0; var messages = new List(); for (var i = 1; i < 100; i++) { var message = i + Environment.NewLine; requestLength += message.Length; messages.Add(message); } await connection.Send( "POST /ReadAndWriteEchoLines HTTP/1.0", $"Content-Length: {requestLength}", "Host: localhost", "", ""); await connection.Receive( "HTTP/1.1 200 OK", ""); await connection.ReceiveHeaders(); foreach (var message in messages) { await connection.Send(message); await connection.Receive(message); } await connection.Send("\r\n"); await connection.WaitForConnectionClose(); } } [ConditionalFact] public async Task ConsumePartialBody() { using (var connection = _fixture.CreateTestConnection()) { var message = "Hello"; await connection.Send( "POST /ReadPartialBody HTTP/1.1", $"Content-Length: {100}", "Host: localhost", "Connection: close", "", ""); await connection.Send(message); await connection.Receive( "HTTP/1.1 200 OK", ""); // This test can return both content length or chunked response // depending on if appfunc managed to complete before write was // issued var headers = await connection.ReceiveHeaders(); if (headers.Contains("Content-Length: 5")) { await connection.Receive("Hello"); } else { await connection.Receive( "5", message, ""); await connection.Receive( "0", "", ""); } await connection.WaitForConnectionClose(); } } } }