I propose to expose a public safe handle type with methods to set and query custom options.
These methods would be a direct wrappers around WinHttpSetOption
and WinHttpQueryOption
,
similarly to the concept of Socket.SetRawSocketOption
.
public class SafeWinHttpHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid
{
public uint GetWinHttpOption(uint option);
public void SetWinHttpOption(uint option, uint optionData);
public void GetWinHttpOption(uint option, System.Span<byte> optionData);
public void SetWinHttpOption(uint option, System.ReadOnlySpan<byte> optionData);
}
Since there is no control on lifecycle of the Session and Request handles, let's expose callbacks for which get invoked by WinHttpHandler
internally.
public class WinHttpHandler : System.Net.Http.HttpMessageHandler
{
public Action<SafeWinHttpHandle> ConfigureWinHttpSession { get; set; }
public Action<SafeWinHttpHandle> ConfigureWinHttpRequest { get; set; }
}
struct tcp_keepalive
{
public uint onoff;
public uint keepalivetime;
public uint keepaliveinterval;
public override string ToString() => $"onoff:{onoff}, keepalivetime:{keepalivetime}, keepaliveinterval:{keepaliveinterval}";
};
const uint WINHTTP_OPTION_TCP_KEEPALIVE = 152;
public async Task SendRequestAsync()
{
var handler = new WinHttpHandler
{
ConfigureWinHttpSession = h =>
{
tcp_keepalive[] readBuffer = new tcp_keepalive[1];
h.GetWinHttpOption(WINHTTP_OPTION_TCP_KEEPALIVE, MemoryMarshal.AsBytes<tcp_keepalive>(readBuffer));
Console.WriteLine($"WINHTTP_OPTION_TCP_KEEPALIVE before: {readBuffer[0]}");
tcp_keepalive[] writeBuffer = new tcp_keepalive[]
{
new tcp_keepalive
{
onoff = 1,
keepalivetime = 54321,
keepaliveinterval = 12345
}
};
h.SetWinHttpOption(WINHTTP_OPTION_TCP_KEEPALIVE, MemoryMarshal.AsBytes<tcp_keepalive>(writeBuffer));
h.GetWinHttpOption(WINHTTP_OPTION_TCP_KEEPALIVE, MemoryMarshal.AsBytes<tcp_keepalive>(readBuffer));
Console.WriteLine($"WINHTTP_OPTION_TCP_KEEPALIVE before: {readBuffer[0]}");
}
};
using var client = new HttpClient(handler);
HttpResponseMessage response = await client.GetAsync(System.Net.Test.Common.Configuration.Http.RemoteEchoServer);
string responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseContent);
}