diff --git a/src/Microsoft.AspNetCore.TestHost/ClientHandler.cs b/src/Microsoft.AspNetCore.TestHost/ClientHandler.cs index 87454d7530..f74b774785 100644 --- a/src/Microsoft.AspNetCore.TestHost/ClientHandler.cs +++ b/src/Microsoft.AspNetCore.TestHost/ClientHandler.cs @@ -126,49 +126,51 @@ namespace Microsoft.AspNetCore.TestHost } var contextFeatures = new FeatureCollection(); - contextFeatures.Set(new RequestFeature()); + var requestFeature = new RequestFeature(); + contextFeatures.Set(requestFeature); _responseFeature = new ResponseFeature(); contextFeatures.Set(_responseFeature); - Context = application.CreateContext(contextFeatures); - var httpContext = Context.HttpContext; + var requestLifetimeFeature = new HttpRequestLifetimeFeature(); + contextFeatures.Set(requestLifetimeFeature); - var serverRequest = httpContext.Request; - serverRequest.Protocol = "HTTP/" + request.Version.ToString(2); - serverRequest.Scheme = request.RequestUri.Scheme; - serverRequest.Method = request.Method.ToString(); + requestFeature.Protocol = "HTTP/" + request.Version.ToString(fieldCount: 2); + requestFeature.Scheme = request.RequestUri.Scheme; + requestFeature.Method = request.Method.ToString(); var fullPath = PathString.FromUriComponent(request.RequestUri); PathString remainder; if (fullPath.StartsWithSegments(pathBase, out remainder)) { - serverRequest.PathBase = pathBase; - serverRequest.Path = remainder; + requestFeature.PathBase = pathBase.Value; + requestFeature.Path = remainder.Value; } else { - serverRequest.PathBase = PathString.Empty; - serverRequest.Path = fullPath; + requestFeature.PathBase = string.Empty; + requestFeature.Path = fullPath.Value; } - serverRequest.QueryString = QueryString.FromUriComponent(request.RequestUri); + requestFeature.QueryString = QueryString.FromUriComponent(request.RequestUri).Value; foreach (var header in request.Headers) { - serverRequest.Headers.Append(header.Key, header.Value.ToArray()); + requestFeature.Headers.Append(header.Key, header.Value.ToArray()); } var requestContent = request.Content; if (requestContent != null) { foreach (var header in request.Content.Headers) { - serverRequest.Headers.Append(header.Key, header.Value.ToArray()); + requestFeature.Headers.Append(header.Key, header.Value.ToArray()); } } _responseStream = new ResponseStream(ReturnResponseMessageAsync, AbortRequest); - httpContext.Response.Body = _responseStream; - httpContext.Response.StatusCode = 200; - httpContext.RequestAborted = _requestAbortedSource.Token; + _responseFeature.Body = _responseStream; + _responseFeature.StatusCode = 200; + requestLifetimeFeature.RequestAborted = _requestAbortedSource.Token; + + Context = application.CreateContext(contextFeatures); } public Context Context { get; private set; } diff --git a/test/Microsoft.AspNetCore.TestHost.Tests/ClientHandlerTests.cs b/test/Microsoft.AspNetCore.TestHost.Tests/ClientHandlerTests.cs index 15f1c28e72..ffb1d7a679 100644 --- a/test/Microsoft.AspNetCore.TestHost.Tests/ClientHandlerTests.cs +++ b/test/Microsoft.AspNetCore.TestHost.Tests/ClientHandlerTests.cs @@ -49,6 +49,31 @@ namespace Microsoft.AspNetCore.TestHost return httpClient.GetAsync("https://example.com/A/Path/and/file.txt?and=query"); } + [Fact] + public Task ExpectedKeysAreInFeatures() + { + var handler = new ClientHandler(new PathString("/A/Path/"), new InspectingApplication(features => + { + // TODO: Assert.True(context.RequestAborted.CanBeCanceled); + Assert.Equal("HTTP/1.1", features.Get().Protocol); + Assert.Equal("GET", features.Get().Method); + Assert.Equal("https", features.Get().Scheme); + Assert.Equal("/A/Path", features.Get().PathBase); + Assert.Equal("/and/file.txt", features.Get().Path); + Assert.Equal("?and=query", features.Get().QueryString); + Assert.NotNull(features.Get().Body); + Assert.NotNull(features.Get().Headers); + Assert.NotNull(features.Get().Headers); + Assert.NotNull(features.Get().Body); + Assert.Equal(200, features.Get().StatusCode); + Assert.Null(features.Get().ReasonPhrase); + Assert.Equal("example.com", features.Get().Headers["host"]); + Assert.NotNull(features.Get()); + })); + var httpClient = new HttpClient(handler); + return httpClient.GetAsync("https://example.com/A/Path/and/file.txt?and=query"); + } + [Fact] public Task SingleSlashNotMovedToPathBase() { @@ -274,6 +299,35 @@ namespace Microsoft.AspNetCore.TestHost } } + private class InspectingApplication : IHttpApplication + { + Action _inspector; + + public InspectingApplication(Action inspector) + { + _inspector = inspector; + } + + public Context CreateContext(IFeatureCollection contextFeatures) + { + _inspector(contextFeatures); + return new Context() + { + HttpContext = new DefaultHttpContext(contextFeatures) + }; + } + + public void DisposeContext(Context context, Exception exception) + { + + } + + public Task ProcessRequestAsync(Context context) + { + return Task.FromResult(0); + } + } + [ConditionalFact] [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Hangs randomly (issue #507)")]