internal protected override Task <HttpResponse> HandleRequest( TestContext ctx, HttpOperation operation, HttpConnection connection, HttpRequest request, RequestFlags effectiveFlags, CancellationToken cancellationToken) { var keepAlive = (effectiveFlags & (RequestFlags.KeepAlive | RequestFlags.CloseConnection)) == RequestFlags.KeepAlive; var redirect = operation.RegisterRedirect(ctx, Target); var response = HttpResponse.CreateRedirect(Code, redirect.Uri); if (keepAlive) { response.KeepAlive = true; } if (operation.HasAnyFlags(HttpOperationFlags.ClientDoesNotSendRedirect)) { redirect.Listener.UnregisterOperation(redirect); } else { response.Redirect = redirect; } return(Task.FromResult(response)); }
protected internal override async Task <HttpResponse> HandleRequest( TestContext ctx, HttpOperation operation, HttpConnection connection, HttpRequest request, RequestFlags effectiveFlags, CancellationToken cancellationToken) { AuthenticationState state; var response = Manager.HandleAuthentication(ctx, connection, request, out state); if (request.Method == "GET" || request.Method == "HEAD" || request.Body == null) { if (request.Headers.TryGetValue("Transfer-Encoding", out string transferEncoding)) { ctx.AssertFail($"Must not send 'Transfer-Encoding' header with '${request.Method}' request."); } if (request.Headers.TryGetValue("Content-Length", out string contentLength)) { ctx.AssertFail($"Must not send 'Content-Length' header with '${request.Method}' request."); } } else if (state == AuthenticationState.Challenge) { if (request.Headers.TryGetValue("Content-Length", out string contentLength)) { ctx.Assert(int.Parse(contentLength), Is.EqualTo(0), "Must send zero-length content with NTLM challenge."); } else { ctx.AssertFail("Must send 'Content-Length: 0' with NTLM challenge."); } } else { if (request.Headers.TryGetValue("Transfer-Encoding", out string transferEncoding)) { ctx.Assert(transferEncoding, Is.EqualTo("chunked"), "Transfer-Encoding"); } else if (!request.Headers.TryGetValue("Content-Length", out string contentLength)) { ctx.AssertFail("Need either 'Transfer-Encoding' or 'Content-Length'"); } } var keepAlive = (effectiveFlags & (RequestFlags.KeepAlive | RequestFlags.CloseConnection)) == RequestFlags.KeepAlive; if (response != null) { response.Redirect = operation.RegisterRedirect(ctx, this, request.Path); return(response); } effectiveFlags |= RequestFlags.Redirected; cancellationToken.ThrowIfCancellationRequested(); return(await Target.HandleRequest(ctx, operation, connection, request, effectiveFlags, cancellationToken)); }
protected internal override async Task <HttpResponse> HandleRequest( TestContext ctx, HttpOperation operation, HttpConnection connection, HttpRequest request, RequestFlags effectiveFlags, CancellationToken cancellationToken) { if (RemoteEndPoint == null) { RemoteEndPoint = connection.RemoteEndPoint; } switch (TestRunner.EffectiveType) { case HttpInstrumentationTestType.CloseIdleConnection: case HttpInstrumentationTestType.CloseCustomConnectionGroup: case HttpInstrumentationTestType.AbortResponse: ctx.Assert(request.Method, Is.EqualTo("GET"), "method"); break; case HttpInstrumentationTestType.ReuseConnection2: ctx.Assert(request.Method, Is.EqualTo("POST"), "method"); break; case HttpInstrumentationTestType.NtlmInstrumentation: case HttpInstrumentationTestType.NtlmClosesConnection: case HttpInstrumentationTestType.NtlmReusesConnection: case HttpInstrumentationTestType.ParallelNtlm: case HttpInstrumentationTestType.NtlmWhileQueued: case HttpInstrumentationTestType.NtlmWhileQueued2: return(await HandleNtlmRequest( ctx, operation, connection, request, effectiveFlags, cancellationToken).ConfigureAwait(false)); case HttpInstrumentationTestType.ReuseConnection: case HttpInstrumentationTestType.ReuseCustomConnectionGroup: case HttpInstrumentationTestType.RedirectOnSameConnection: ctx.Assert(request.Method, Is.EqualTo("GET"), "method"); AssertReusingConnection(ctx, connection); break; case HttpInstrumentationTestType.ReuseAfterPartialRead: // We can't reuse the connection because we did not read the entire response. ctx.Assert(request.Method, Is.EqualTo("GET"), "method"); AssertNotReusingConnection(ctx, connection); break; case HttpInstrumentationTestType.CustomConnectionGroup: // We can't reuse the connection because we're in a different connection group. ctx.Assert(request.Method, Is.EqualTo("GET"), "method"); AssertNotReusingConnection(ctx, connection); break; default: throw ctx.AssertFail(TestRunner.EffectiveType); } HttpResponse response; HttpInstrumentationContent content; ListenerOperation redirect; switch (TestRunner.EffectiveType) { case HttpInstrumentationTestType.ReuseAfterPartialRead: return(new HttpResponse(HttpStatusCode.OK, Content) { WriteAsBlob = true }); case HttpInstrumentationTestType.AbortResponse: content = new HttpInstrumentationContent(TestRunner, currentRequest); return(new HttpResponse(HttpStatusCode.OK, content)); case HttpInstrumentationTestType.ReuseConnection2: return(new HttpResponse(HttpStatusCode.OK, Content)); case HttpInstrumentationTestType.RedirectOnSameConnection: redirect = operation.RegisterRedirect(ctx, Target); response = HttpResponse.CreateRedirect(HttpStatusCode.Redirect, redirect); response.SetBody(new StringContent($"{ME} Redirecting")); response.WriteAsBlob = true; return(response); default: return(HttpResponse.CreateSuccess(ME)); } }
async Task <HttpResponse> HandleNtlmRequest( TestContext ctx, HttpOperation operation, HttpConnection connection, HttpRequest request, RequestFlags effectiveFlags, CancellationToken cancellationToken) { var me = $"{ME}.{nameof (HandleNtlmRequest)}"; ctx.LogDebug(3, $"{me}: {connection.RemoteEndPoint}"); AuthenticationState state; var response = AuthManager.HandleAuthentication(ctx, connection, request, out state); ctx.LogDebug(3, $"{me}: {connection.RemoteEndPoint} - {state} {response}"); if (state == AuthenticationState.Unauthenticated) { ctx.Assert(currentAuthState, Is.EqualTo(AuthenticationState.None), "first request"); currentAuthState = AuthenticationState.Unauthenticated; } else if (TestRunner.EffectiveType == HttpInstrumentationTestType.NtlmInstrumentation) { if (state == AuthenticationState.Challenge) { ctx.LogDebug(3, $"{me}: {connection.RemoteEndPoint} {RemoteEndPoint}"); challengeEndPoint = connection.RemoteEndPoint; } else { ctx.Assert(connection.RemoteEndPoint, Is.EqualTo(challengeEndPoint), "must reuse connection"); } } if (TestRunner.EffectiveType == HttpInstrumentationTestType.ParallelNtlm) { var parallelOperation = TestRunner.StartParallelNtlm( ctx, this, state, cancellationToken); if (parallelOperation != null) { await parallelOperation.WaitForCompletion().ConfigureAwait(false); } } var keepAlive = !CloseConnection && (effectiveFlags & (RequestFlags.KeepAlive | RequestFlags.CloseConnection)) == RequestFlags.KeepAlive; if (response != null) { response.Redirect = operation.RegisterRedirect(ctx, this, request.Path); return(response); } cancellationToken.ThrowIfCancellationRequested(); HttpInstrumentationContent content; switch (TestRunner.EffectiveType) { case HttpInstrumentationTestType.NtlmWhileQueued: content = new HttpInstrumentationContent(TestRunner, currentRequest); return(new HttpResponse(HttpStatusCode.OK, content)); case HttpInstrumentationTestType.NtlmWhileQueued2: content = new HttpInstrumentationContent(TestRunner, currentRequest); return(new HttpResponse(HttpStatusCode.OK, content) { CloseConnection = true }); } var ret = await Target.HandleRequest(ctx, operation, connection, request, effectiveFlags, cancellationToken); ctx.LogDebug(3, $"{me} target done: {Target} {ret}"); ret.KeepAlive = false; return(ret); }
protected internal override async Task<HttpResponse> HandleRequest ( TestContext ctx, HttpOperation operation, HttpConnection connection, HttpRequest request, RequestFlags effectiveFlags, CancellationToken cancellationToken) { switch (TestRunner.EffectiveType) { case HttpRequestTestType.LargeHeader: case HttpRequestTestType.LargeHeader2: case HttpRequestTestType.SendResponseAsBlob: case HttpRequestTestType.CloseRequestStream: case HttpRequestTestType.ReadTimeout: case HttpRequestTestType.SimpleGZip: case HttpRequestTestType.TestResponseStream: case HttpRequestTestType.LargeChunkRead: case HttpRequestTestType.LargeGZipRead: case HttpRequestTestType.GZipWithLength: case HttpRequestTestType.ResponseStreamCheckLength2: case HttpRequestTestType.ResponseStreamCheckLength: case HttpRequestTestType.GetNoLength: ctx.Assert (request.Method, Is.EqualTo ("GET"), "method"); break; case HttpRequestTestType.ServerAbortsPost: ctx.Assert (request.Method, Is.EqualTo ("POST"), "method"); break; case HttpRequestTestType.RedirectNoLength: case HttpRequestTestType.PutChunked: case HttpRequestTestType.PutChunkDontCloseRequest: case HttpRequestTestType.ServerAbortsRedirect: break; case HttpRequestTestType.EntityTooBig: await EntityTooBig ().ConfigureAwait (false); return null; case HttpRequestTestType.PostChunked: return await HandlePostChunked ( ctx, operation, connection, request, effectiveFlags, cancellationToken).ConfigureAwait (false); case HttpRequestTestType.PostContentLength: await PostContentLength ().ConfigureAwait (false); break; case HttpRequestTestType.ClientAbortsPost: await ClientAbortsPost ().ConfigureAwait (false); return null; case HttpRequestTestType.ImplicitHost: var hostAndPort = TestRunner.Uri.GetComponents (UriComponents.HostAndPort, UriFormat.Unescaped); ctx.Assert (request.Headers["Host"], Is.EqualTo (hostAndPort), "host"); break; case HttpRequestTestType.CustomHost: ctx.Assert (request.Headers["Host"], Is.EqualTo ("custom"), "host"); break; case HttpRequestTestType.CustomHostWithPort: ctx.Assert (request.Headers["Host"], Is.EqualTo ("custom:8888"), "host"); break; case HttpRequestTestType.CustomHostDefaultPort: var defaultPort = TestRunner.Server.UseSSL ? 443 : 80; ctx.Assert (request.Headers["Host"], Is.EqualTo ($"custom:{defaultPort}"), "host"); break; default: throw ctx.AssertFail (TestRunner.EffectiveType); } RemoteEndPoint = connection.RemoteEndPoint; HttpResponse response; HttpRequestContent content; ListenerOperation redirect; switch (TestRunner.EffectiveType) { case HttpRequestTestType.LargeHeader: response = new HttpResponse (HttpStatusCode.OK, Content); response.AddHeader ("LargeTest", ConnectionHandler.GetLargeText (100)); return response; case HttpRequestTestType.LargeHeader2: response = new HttpResponse (HttpStatusCode.OK, Content); response.AddHeader ("LargeTest", ConnectionHandler.GetLargeText (100)); response.WriteAsBlob = true; return response; case HttpRequestTestType.SendResponseAsBlob: return new HttpResponse (HttpStatusCode.OK, Content) { WriteAsBlob = true }; case HttpRequestTestType.ReadTimeout: content = new HttpRequestContent (TestRunner, currentRequest); return new HttpResponse (HttpStatusCode.OK, content); case HttpRequestTestType.RedirectNoLength: redirect = operation.RegisterRedirect (ctx, Target); response = HttpResponse.CreateRedirect (HttpStatusCode.Redirect, redirect); response.NoContentLength = true; return response; case HttpRequestTestType.ServerAbortsRedirect: if (isSecondRequest) throw ctx.AssertFail ("Should never happen."); var cloned = new HttpRequestHandler (this); cloned.isSecondRequest = true; redirect = operation.RegisterRedirect (ctx, cloned); response = HttpResponse.CreateRedirect (HttpStatusCode.Redirect, redirect); return response; case HttpRequestTestType.ServerAbortsPost: return new HttpResponse (HttpStatusCode.BadRequest, Content); case HttpRequestTestType.SimpleGZip: var gzipContent = new GZipContent (ConnectionHandler.TheQuickBrownFoxBuffer); return new HttpResponse (HttpStatusCode.OK, gzipContent); case HttpRequestTestType.TestResponseStream: response = new HttpResponse (HttpStatusCode.OK, Content); response.WriteAsBlob = true; return response; case HttpRequestTestType.LargeChunkRead: response = new HttpResponse (HttpStatusCode.OK, Content); response.WriteBodyAsBlob = true; return response; case HttpRequestTestType.LargeGZipRead: gzipContent = new GZipContent ((ChunkedContent)Content); response = new HttpResponse (HttpStatusCode.OK, gzipContent); return response; case HttpRequestTestType.GZipWithLength: gzipContent = new GZipContent ((StringContent)Content); response = new HttpResponse (HttpStatusCode.OK, gzipContent); return response; case HttpRequestTestType.ResponseStreamCheckLength2: case HttpRequestTestType.ResponseStreamCheckLength: response = new HttpResponse (HttpStatusCode.OK, Content); return response; case HttpRequestTestType.GetNoLength: content = new HttpRequestContent (TestRunner, currentRequest); return new HttpResponse (HttpStatusCode.OK, content); default: return HttpResponse.CreateSuccess (ME); } async Task EntityTooBig () { await request.ReadHeaders (ctx, cancellationToken).ConfigureAwait (false); await ctx.AssertException<IOException> (() => request.Read (ctx, cancellationToken), "client doesn't send any body"); } async Task ClientAbortsPost () { await request.ReadHeaders (ctx, cancellationToken).ConfigureAwait (false); await ctx.AssertException<IOException> (() => request.Read (ctx, cancellationToken), "client doesn't send any body"); } async Task PostContentLength () { await request.ReadHeaders (ctx, cancellationToken).ConfigureAwait (false); ctx.Assert (request.ContentLength, Is.EqualTo (currentRequest.Content.Length), "request.ContentLength"); readyTcs.TrySetResult (true); await request.Read (ctx, cancellationToken); } }