예제 #1
0
        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));
        }
예제 #2
0
        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);
        }
예제 #5
0
		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);
			}
		}