Skip to content

Commit 72a2054

Browse files
committed
Add HTTPS support to http2cat
1 parent e1d2bb6 commit 72a2054

File tree

2 files changed

+89
-39
lines changed

2 files changed

+89
-39
lines changed

src/Servers/Kestrel/samples/http2cat/Http2Utilities.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class Http2Utilities : IHttpHeadersHandler
3030
{
3131
new KeyValuePair<string, string>(HeaderNames.Method, "GET"),
3232
new KeyValuePair<string, string>(HeaderNames.Path, "/"),
33-
new KeyValuePair<string, string>(HeaderNames.Scheme, "http"),
33+
new KeyValuePair<string, string>(HeaderNames.Scheme, "https"),
3434
new KeyValuePair<string, string>(HeaderNames.Authority, "localhost:80"),
3535
new KeyValuePair<string, string>("user-agent", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:54.0) Gecko/20100101 Firefox/54.0"),
3636
new KeyValuePair<string, string>("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"),
@@ -43,7 +43,7 @@ public class Http2Utilities : IHttpHeadersHandler
4343
{
4444
new KeyValuePair<string, string>(HeaderNames.Method, "POST"),
4545
new KeyValuePair<string, string>(HeaderNames.Path, "/"),
46-
new KeyValuePair<string, string>(HeaderNames.Scheme, "http"),
46+
new KeyValuePair<string, string>(HeaderNames.Scheme, "https"),
4747
new KeyValuePair<string, string>(HeaderNames.Authority, "localhost:80"),
4848
};
4949

@@ -52,7 +52,7 @@ public class Http2Utilities : IHttpHeadersHandler
5252
new KeyValuePair<string, string>(HeaderNames.Method, "POST"),
5353
new KeyValuePair<string, string>(HeaderNames.Path, "/"),
5454
new KeyValuePair<string, string>(HeaderNames.Authority, "127.0.0.1"),
55-
new KeyValuePair<string, string>(HeaderNames.Scheme, "http"),
55+
new KeyValuePair<string, string>(HeaderNames.Scheme, "https"),
5656
new KeyValuePair<string, string>("expect", "100-continue"),
5757
};
5858

@@ -66,7 +66,7 @@ public class Http2Utilities : IHttpHeadersHandler
6666
{
6767
new KeyValuePair<string, string>(HeaderNames.Method, "GET"),
6868
new KeyValuePair<string, string>(HeaderNames.Path, "/"),
69-
new KeyValuePair<string, string>(HeaderNames.Scheme, "http"),
69+
new KeyValuePair<string, string>(HeaderNames.Scheme, "https"),
7070
new KeyValuePair<string, string>(HeaderNames.Authority, "localhost:80"),
7171
new KeyValuePair<string, string>("a", _4kHeaderValue),
7272
new KeyValuePair<string, string>("b", _4kHeaderValue),
@@ -78,7 +78,7 @@ public class Http2Utilities : IHttpHeadersHandler
7878
{
7979
new KeyValuePair<string, string>(HeaderNames.Method, "GET"),
8080
new KeyValuePair<string, string>(HeaderNames.Path, "/"),
81-
new KeyValuePair<string, string>(HeaderNames.Scheme, "http"),
81+
new KeyValuePair<string, string>(HeaderNames.Scheme, "https"),
8282
new KeyValuePair<string, string>(HeaderNames.Authority, "localhost:80"),
8383
new KeyValuePair<string, string>("a", _4kHeaderValue),
8484
new KeyValuePair<string, string>("b", _4kHeaderValue),
@@ -93,7 +93,7 @@ public static IEnumerable<KeyValuePair<string, string>> ReadRateRequestHeaders(i
9393
{
9494
new KeyValuePair<string, string>(HeaderNames.Method, "POST"),
9595
new KeyValuePair<string, string>(HeaderNames.Path, "/" + expectedBytes),
96-
new KeyValuePair<string, string>(HeaderNames.Scheme, "http"),
96+
new KeyValuePair<string, string>(HeaderNames.Scheme, "https"),
9797
new KeyValuePair<string, string>(HeaderNames.Authority, "localhost:80"),
9898
};
9999

src/Servers/Kestrel/samples/http2cat/Program.cs

Lines changed: 83 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System;
5+
using System.Collections.Generic;
46
using System.Diagnostics;
7+
using System.IO;
8+
using System.IO.Pipelines;
59
using System.Net;
10+
using System.Net.Security;
11+
using System.Security.Authentication;
612
using System.Text;
13+
using System.Threading;
714
using System.Threading.Tasks;
815
using Microsoft.AspNetCore.Connections;
16+
using Microsoft.AspNetCore.Connections.Features;
17+
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
918
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
1019
using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Client;
1120
using Microsoft.Extensions.DependencyInjection;
@@ -46,65 +55,106 @@ public Http2CatHostedService(IConnectionFactory connectionFactory, ILogger<Http2
4655

4756
public async Task RunAsync()
4857
{
49-
var endpoint = new IPEndPoint(IPAddress.Loopback, 5005);
58+
var endpoint = new IPEndPoint(IPAddress.Loopback, 5001);
5059

5160
_logger.LogInformation($"Connecting to '{endpoint}'.");
5261

53-
await using var connectionContext = await _connectionFactory.ConnectAsync(endpoint);
62+
await using var context = await _connectionFactory.ConnectAsync(endpoint);
5463

55-
_logger.LogInformation($"Connected to '{endpoint}'.");
64+
_logger.LogInformation($"Connected to '{endpoint}'. Starting TLS handshake.");
5665

57-
var http2Utilities = new Http2Utilities(connectionContext);
66+
var memoryPool = context.Features.Get<IMemoryPoolFeature>()?.MemoryPool;
67+
var inputPipeOptions = new StreamPipeReaderOptions(memoryPool, memoryPool.GetMinimumSegmentSize(), memoryPool.GetMinimumAllocSize(), leaveOpen: true);
68+
var outputPipeOptions = new StreamPipeWriterOptions(pool: memoryPool, leaveOpen: true);
5869

59-
await http2Utilities.InitializeConnectionAsync();
70+
await using var sslDuplexPipe = new SslDuplexPipe(context.Transport, inputPipeOptions, outputPipeOptions);
71+
await using var sslStream = sslDuplexPipe.Stream;
6072

61-
_logger.LogInformation("Initialized http2 connection. Starting stream 1.");
73+
var originalTransport = context.Transport;
74+
context.Transport = sslDuplexPipe;
6275

63-
await http2Utilities.StartStreamAsync(1, Http2Utilities._browserRequestHeaders, endStream: true);
76+
try
77+
{
78+
await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
79+
{
80+
TargetHost = "localhost",
81+
RemoteCertificateValidationCallback = (_, __, ___, ____) => true,
82+
ApplicationProtocols = new List<SslApplicationProtocol> { SslApplicationProtocol.Http2 },
83+
EnabledSslProtocols = SslProtocols.Tls12,
84+
}, CancellationToken.None);
6485

65-
var headersFrame = await http2Utilities.ReceiveFrameAsync();
86+
_logger.LogInformation($"TLS handshake completed successfully.");
6687

67-
Trace.Assert(headersFrame.Type == Http2FrameType.HEADERS);
68-
Trace.Assert((headersFrame.Flags & (byte)Http2HeadersFrameFlags.END_HEADERS) != 0);
69-
Trace.Assert((headersFrame.Flags & (byte)Http2HeadersFrameFlags.END_STREAM) == 0);
88+
var http2Utilities = new Http2Utilities(context);
7089

71-
_logger.LogInformation("Received headers in a single frame.");
90+
await http2Utilities.InitializeConnectionAsync();
7291

73-
var decodedHeaders = http2Utilities.DecodeHeaders(headersFrame);
74-
75-
foreach (var header in decodedHeaders)
76-
{
77-
_logger.LogInformation($"{header.Key}: {header.Value}");
78-
}
92+
_logger.LogInformation("Initialized http2 connection. Starting stream 1.");
93+
94+
await http2Utilities.StartStreamAsync(1, Http2Utilities._browserRequestHeaders, endStream: true);
95+
96+
var headersFrame = await http2Utilities.ReceiveFrameAsync();
97+
98+
Trace.Assert(headersFrame.Type == Http2FrameType.HEADERS);
99+
Trace.Assert((headersFrame.Flags & (byte)Http2HeadersFrameFlags.END_HEADERS) != 0);
100+
Trace.Assert((headersFrame.Flags & (byte)Http2HeadersFrameFlags.END_STREAM) == 0);
101+
102+
_logger.LogInformation("Received headers in a single frame.");
103+
104+
var decodedHeaders = http2Utilities.DecodeHeaders(headersFrame);
105+
106+
foreach (var header in decodedHeaders)
107+
{
108+
_logger.LogInformation($"{header.Key}: {header.Value}");
109+
}
110+
111+
var dataFrame = await http2Utilities.ReceiveFrameAsync();
79112

80-
var dataFrame = await http2Utilities.ReceiveFrameAsync();
113+
Trace.Assert(dataFrame.Type == Http2FrameType.DATA);
114+
Trace.Assert((dataFrame.Flags & (byte)Http2DataFrameFlags.END_STREAM) == 0);
81115

82-
Trace.Assert(dataFrame.Type == Http2FrameType.DATA);
83-
Trace.Assert((dataFrame.Flags & (byte)Http2DataFrameFlags.END_STREAM) == 0);
116+
_logger.LogInformation("Received data in a single frame.");
84117

85-
_logger.LogInformation("Received data in a single frame.");
118+
_logger.LogInformation(Encoding.UTF8.GetString(dataFrame.Payload.ToArray()));
86119

87-
_logger.LogInformation(Encoding.UTF8.GetString(dataFrame.Payload.ToArray()));
120+
var trailersFrame = await http2Utilities.ReceiveFrameAsync();
88121

89-
var trailersFrame = await http2Utilities.ReceiveFrameAsync();
122+
Trace.Assert(trailersFrame.Type == Http2FrameType.HEADERS);
123+
Trace.Assert((trailersFrame.Flags & (byte)Http2DataFrameFlags.END_STREAM) == 1);
90124

91-
Trace.Assert(trailersFrame.Type == Http2FrameType.HEADERS);
92-
Trace.Assert((trailersFrame.Flags & (byte)Http2DataFrameFlags.END_STREAM) == 1);
125+
_logger.LogInformation("Received trailers in a single frame.");
93126

94-
_logger.LogInformation("Received trailers in a single frame.");
127+
http2Utilities._decodedHeaders.Clear();
95128

96-
http2Utilities._decodedHeaders.Clear();
129+
var decodedTrailers = http2Utilities.DecodeHeaders(trailersFrame);
97130

98-
var decodedTrailers = http2Utilities.DecodeHeaders(trailersFrame);
131+
foreach (var header in decodedHeaders)
132+
{
133+
_logger.LogInformation($"{header.Key}: {header.Value}");
134+
}
99135

100-
foreach (var header in decodedHeaders)
136+
await http2Utilities.StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false);
137+
138+
_logger.LogInformation("Connection stopped.");
139+
}
140+
finally
101141
{
102-
_logger.LogInformation($"{header.Key}: {header.Value}");
142+
context.Transport = originalTransport;
103143
}
144+
}
145+
}
104146

105-
await http2Utilities.StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false);
147+
private class SslDuplexPipe : DuplexPipeStreamAdapter<SslStream>
148+
{
149+
public SslDuplexPipe(IDuplexPipe transport, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions)
150+
: this(transport, readerOptions, writerOptions, s => new SslStream(s))
151+
{
152+
153+
}
106154

107-
_logger.LogInformation("Connection stopped.");
155+
public SslDuplexPipe(IDuplexPipe transport, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions, Func<Stream, SslStream> factory) :
156+
base(transport, readerOptions, writerOptions, factory)
157+
{
108158
}
109159
}
110160
}

0 commit comments

Comments
 (0)