async Task <bool> ReuseConnection(TestContext ctx, HttpOperation operation, CancellationToken cancellationToken) { var me = $"{ME}({connection.ME}) REUSE"; ctx.LogDebug(2, $"{me}"); cancellationToken.ThrowIfCancellationRequested(); var reusable = await connection.ReuseConnection(ctx, cancellationToken).ConfigureAwait(false); ctx.LogDebug(2, $"{me} #1: {reusable}"); if (reusable && (operation?.HasAnyFlags(HttpOperationFlags.ClientUsesNewConnection) ?? false)) { try { await connection.ReadRequest(ctx, cancellationToken).ConfigureAwait(false); throw ctx.AssertFail("Expected client to use a new connection."); } catch (OperationCanceledException) { throw; } catch (Exception ex) { ctx.LogDebug(2, $"{ME} EXPECTED EXCEPTION: {ex.GetType ()} {ex.Message}"); } connection.Dispose(); return(false); } return(reusable); }
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)); }
public async Task <HttpResponse> HandleRequest(TestContext ctx, HttpOperation operation, HttpConnection connection, HttpRequest request, CancellationToken cancellationToken) { Exception originalError; HttpResponse response; if (operation == null) { throw new ArgumentNullException(nameof(operation)); } if (connection == null) { throw new ArgumentNullException(nameof(connection)); } var expectServerError = operation.HasAnyFlags(HttpOperationFlags.ExpectServerException); try { Debug(ctx, 1, $"HANDLE REQUEST: {connection.RemoteEndPoint}"); DumpHeaders(ctx, request); connection.Server.CheckEncryption(ctx, connection.SslStream); response = await HandleRequest(ctx, operation, connection, request, Flags, cancellationToken); if (response == null) { response = HttpResponse.CreateSuccess(); } if ((Flags & RequestFlags.CloseConnection) != 0) { response.CloseConnection = true; } if (!response.KeepAlive.HasValue && ((Flags & RequestFlags.KeepAlive) != 0)) { response.KeepAlive = true; } response.ResolveHeaders(); Debug(ctx, 1, $"HANDLE REQUEST DONE: {connection.RemoteEndPoint}", response); DumpHeaders(ctx, response); return(response); } catch (AssertionException ex) { originalError = ex; response = HttpResponse.CreateError(ex.Message); } catch (OperationCanceledException) { throw; } catch (Exception ex) { originalError = ex; response = HttpResponse.CreateError("Caught unhandled exception", ex); } if (ctx.IsCanceled || cancellationToken.IsCancellationRequested) { Debug(ctx, 1, "HANDLE REQUEST - CANCELED"); throw new OperationCanceledException(); } if (originalError is AssertionException) { Debug(ctx, 1, "HANDLE REQUEST - ASSERTION FAILED", originalError); } else if (expectServerError) { Debug(ctx, 1, "HANDLE REQUEST - EXPECTED ERROR", originalError.GetType()); } else { Debug(ctx, 1, "HANDLE REQUEST - ERROR", originalError); } return(response); }
async Task <bool> InitConnection(TestContext ctx, HttpOperation operation, CancellationToken cancellationToken) { var me = $"{ME}({connection.ME}) INIT"; ctx.LogDebug(2, $"{me}"); bool haveRequest; cancellationToken.ThrowIfCancellationRequested(); try { await connection.Initialize(ctx, operation, cancellationToken); ctx.LogDebug(2, $"{me} #1 {connection.RemoteEndPoint}"); if (operation != null && operation.HasAnyFlags(HttpOperationFlags.ServerAbortsHandshake)) { throw ctx.AssertFail("Expected server to abort handshake."); } /* * There seems to be some kind of a race condition here. * * When the client aborts the handshake due the a certificate validation failure, * then we either receive an exception during the TLS handshake or the connection * will be closed when the handshake is completed. * */ haveRequest = await connection.WaitForRequest(cancellationToken); ctx.LogDebug(2, $"{me} #2 {haveRequest}"); if (operation != null && operation.HasAnyFlags(HttpOperationFlags.ClientAbortsHandshake)) { throw ctx.AssertFail("Expected client to abort handshake."); } } catch (Exception ex) { if (operation.HasAnyFlags(HttpOperationFlags.ServerAbortsHandshake, HttpOperationFlags.ClientAbortsHandshake)) { return(false); } ctx.LogDebug(2, $"{me} FAILED: {ex.Message}\n{ex}"); throw; } if (!haveRequest) { ctx.LogMessage($"{me} got empty requets!"); throw ctx.AssertFail("Got empty request."); } if (Server.UseSSL) { ctx.Assert(connection.SslStream.IsAuthenticated, "server is authenticated"); if (operation != null && operation.HasAnyFlags(HttpOperationFlags.RequireClientCertificate)) { ctx.Assert(connection.SslStream.IsMutuallyAuthenticated, "server is mutually authenticated"); } } ctx.LogDebug(2, $"{me} DONE"); return(true); }