Commit 9df31edd authored by Honfika's avatar Honfika

Nullable reference fixes

parent e3c1483f
...@@ -53,11 +53,11 @@ namespace Titanium.Web.Proxy ...@@ -53,11 +53,11 @@ namespace Titanium.Web.Proxy
/// <param name="remoteCertificate">The remote certificate of server.</param> /// <param name="remoteCertificate">The remote certificate of server.</param>
/// <param name="acceptableIssuers">The acceptable issues for client certificate as listed by server.</param> /// <param name="acceptableIssuers">The acceptable issues for client certificate as listed by server.</param>
/// <returns></returns> /// <returns></returns>
internal X509Certificate SelectClientCertificate(object sender, string targetHost, internal X509Certificate? SelectClientCertificate(object sender, string targetHost,
X509CertificateCollection localCertificates, X509CertificateCollection localCertificates,
X509Certificate remoteCertificate, string[] acceptableIssuers) X509Certificate remoteCertificate, string[] acceptableIssuers)
{ {
X509Certificate clientCertificate = null; X509Certificate? clientCertificate = null;
if (acceptableIssuers != null && acceptableIssuers.Length > 0 && localCertificates != null && if (acceptableIssuers != null && acceptableIssuers.Length > 0 && localCertificates != null &&
localCertificates.Count > 0) localCertificates.Count > 0)
......
...@@ -10,16 +10,17 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -10,16 +10,17 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
internal readonly CancellationTokenSource TaskCancellationSource; internal readonly CancellationTokenSource TaskCancellationSource;
internal BeforeSslAuthenticateEventArgs(CancellationTokenSource taskCancellationSource) internal BeforeSslAuthenticateEventArgs(CancellationTokenSource taskCancellationSource, string sniHostName)
{ {
TaskCancellationSource = taskCancellationSource; TaskCancellationSource = taskCancellationSource;
SniHostName = sniHostName;
} }
/// <summary> /// <summary>
/// The server name indication hostname if available. Otherwise the generic certificate hostname of /// The server name indication hostname if available. Otherwise the generic certificate hostname of
/// TransparentEndPoint. /// TransparentEndPoint.
/// </summary> /// </summary>
public string SniHostName { get; internal set; } public string SniHostName { get; }
/// <summary> /// <summary>
/// Should we decrypt the SSL request? /// Should we decrypt the SSL request?
......
...@@ -11,31 +11,31 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -11,31 +11,31 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary> /// <summary>
/// The proxy server instance. /// The proxy server instance.
/// </summary> /// </summary>
public object Sender { get; internal set; } public object? Sender { get; internal set; }
/// <summary> /// <summary>
/// The remote hostname to which we are authenticating against. /// The remote hostname to which we are authenticating against.
/// </summary> /// </summary>
public string TargetHost { get; internal set; } public string? TargetHost { get; internal set; }
/// <summary> /// <summary>
/// Local certificates in store with matching issuers requested by TargetHost website. /// Local certificates in store with matching issuers requested by TargetHost website.
/// </summary> /// </summary>
public X509CertificateCollection LocalCertificates { get; internal set; } public X509CertificateCollection? LocalCertificates { get; internal set; }
/// <summary> /// <summary>
/// Certificate of the remote server. /// Certificate of the remote server.
/// </summary> /// </summary>
public X509Certificate RemoteCertificate { get; internal set; } public X509Certificate? RemoteCertificate { get; internal set; }
/// <summary> /// <summary>
/// Acceptable issuers as listed by remote server. /// Acceptable issuers as listed by remote server.
/// </summary> /// </summary>
public string[] AcceptableIssuers { get; internal set; } public string[]? AcceptableIssuers { get; internal set; }
/// <summary> /// <summary>
/// Client Certificate we selected. Set this value to override. /// Client Certificate we selected. Set this value to override.
/// </summary> /// </summary>
public X509Certificate ClientCertificate { get; set; } public X509Certificate? ClientCertificate { get; set; }
} }
} }
...@@ -70,7 +70,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -70,7 +70,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary> /// <summary>
/// Occurs when multipart request part sent. /// Occurs when multipart request part sent.
/// </summary> /// </summary>
public event EventHandler<MultipartRequestPartSentEventArgs> MultipartRequestPartSent; public event EventHandler<MultipartRequestPartSentEventArgs>? MultipartRequestPartSent;
private ICustomStreamReader getStreamReader(bool isRequest) private ICustomStreamReader getStreamReader(bool isRequest)
{ {
...@@ -105,7 +105,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -105,7 +105,7 @@ namespace Titanium.Web.Proxy.EventArguments
request.ReadHttp2BodyTaskCompletionSource = tcs; request.ReadHttp2BodyTaskCompletionSource = tcs;
// signal to HTTP/2 copy frame method to continue // signal to HTTP/2 copy frame method to continue
request.ReadHttp2BeforeHandlerTaskCompletionSource.SetResult(true); request.ReadHttp2BeforeHandlerTaskCompletionSource!.SetResult(true);
await tcs.Task; await tcs.Task;
...@@ -177,7 +177,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -177,7 +177,7 @@ namespace Titanium.Web.Proxy.EventArguments
response.ReadHttp2BodyTaskCompletionSource = tcs; response.ReadHttp2BodyTaskCompletionSource = tcs;
// signal to HTTP/2 copy frame method to continue // signal to HTTP/2 copy frame method to continue
response.ReadHttp2BeforeHandlerTaskCompletionSource.SetResult(true); response.ReadHttp2BeforeHandlerTaskCompletionSource!.SetResult(true);
await tcs.Task; await tcs.Task;
...@@ -286,7 +286,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -286,7 +286,7 @@ namespace Titanium.Web.Proxy.EventArguments
await copyBodyAsync(false, false, writer, transformation, OnDataReceived, cancellationToken); await copyBodyAsync(false, false, writer, transformation, OnDataReceived, cancellationToken);
} }
private async Task copyBodyAsync(bool isRequest, bool useOriginalHeaderValues, HttpWriter writer, TransformationMode transformation, Action<byte[], int, int> onCopy, CancellationToken cancellationToken) private async Task copyBodyAsync(bool isRequest, bool useOriginalHeaderValues, HttpWriter writer, TransformationMode transformation, Action<byte[], int, int>? onCopy, CancellationToken cancellationToken)
{ {
var stream = getStreamReader(isRequest); var stream = getStreamReader(isRequest);
...@@ -302,9 +302,9 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -302,9 +302,9 @@ namespace Titanium.Web.Proxy.EventArguments
} }
LimitedStream limitedStream; LimitedStream limitedStream;
Stream decompressStream = null; Stream? decompressStream = null;
string contentEncoding = useOriginalHeaderValues ? requestResponse.OriginalContentEncoding : requestResponse.ContentEncoding; string? contentEncoding = useOriginalHeaderValues ? requestResponse.OriginalContentEncoding : requestResponse.ContentEncoding;
Stream s = limitedStream = new LimitedStream(stream, BufferPool, isChunked, contentLength); Stream s = limitedStream = new LimitedStream(stream, BufferPool, isChunked, contentLength);
...@@ -541,7 +541,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -541,7 +541,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="result">The html content bytes.</param> /// <param name="result">The html content bytes.</param>
/// <param name="headers">The HTTP headers.</param> /// <param name="headers">The HTTP headers.</param>
/// <param name="closeServerConnection">Close the server connection used by request if any?</param> /// <param name="closeServerConnection">Close the server connection used by request if any?</param>
public void Ok(byte[] result, Dictionary<string, HttpHeader> headers = null, public void Ok(byte[] result, Dictionary<string, HttpHeader>? headers = null,
bool closeServerConnection = false) bool closeServerConnection = false)
{ {
var response = new OkResponse(); var response = new OkResponse();
...@@ -562,7 +562,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -562,7 +562,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="headers">The HTTP headers.</param> /// <param name="headers">The HTTP headers.</param>
/// <param name="closeServerConnection">Close the server connection used by request if any?</param> /// <param name="closeServerConnection">Close the server connection used by request if any?</param>
public void GenericResponse(string html, HttpStatusCode status, public void GenericResponse(string html, HttpStatusCode status,
Dictionary<string, HttpHeader> headers = null, bool closeServerConnection = false) Dictionary<string, HttpHeader>? headers = null, bool closeServerConnection = false)
{ {
var response = new GenericResponse(status); var response = new GenericResponse(status);
response.HttpVersion = HttpClient.Request.HttpVersion; response.HttpVersion = HttpClient.Request.HttpVersion;
......
...@@ -70,7 +70,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -70,7 +70,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Returns a user data for this request/response session which is /// Returns a user data for this request/response session which is
/// same as the user data of HttpClient. /// same as the user data of HttpClient.
/// </summary> /// </summary>
public object UserData public object? UserData
{ {
get => HttpClient.UserData; get => HttpClient.UserData;
set => HttpClient.UserData = value; set => HttpClient.UserData = value;
...@@ -112,7 +112,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -112,7 +112,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary> /// <summary>
/// Are we using a custom upstream HTTP(S) proxy? /// Are we using a custom upstream HTTP(S) proxy?
/// </summary> /// </summary>
public ExternalProxy CustomUpStreamProxyUsed { get; internal set; } public ExternalProxy? CustomUpStreamProxyUsed { get; internal set; }
/// <summary> /// <summary>
/// Local endpoint via which we make the request. /// Local endpoint via which we make the request.
...@@ -127,7 +127,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -127,7 +127,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary> /// <summary>
/// The last exception that happened. /// The last exception that happened.
/// </summary> /// </summary>
public Exception Exception { get; internal set; } public Exception? Exception { get; internal set; }
/// <summary> /// <summary>
/// Implements cleanup here. /// Implements cleanup here.
...@@ -146,12 +146,12 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -146,12 +146,12 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary> /// <summary>
/// Fired when data is sent within this session to server/client. /// Fired when data is sent within this session to server/client.
/// </summary> /// </summary>
public event EventHandler<DataEventArgs> DataSent; public event EventHandler<DataEventArgs>? DataSent;
/// <summary> /// <summary>
/// Fired when data is received within this session from client/server. /// Fired when data is received within this session from client/server.
/// </summary> /// </summary>
public event EventHandler<DataEventArgs> DataReceived; public event EventHandler<DataEventArgs>? DataReceived;
internal void OnDataSent(byte[] buffer, int offset, int count) internal void OnDataSent(byte[] buffer, int offset, int count)
{ {
......
...@@ -22,7 +22,7 @@ namespace Titanium.Web.Proxy.Exceptions ...@@ -22,7 +22,7 @@ namespace Titanium.Web.Proxy.Exceptions
/// </summary> /// </summary>
/// <param name="message">Exception message</param> /// <param name="message">Exception message</param>
/// <param name="innerException">Inner exception associated</param> /// <param name="innerException">Inner exception associated</param>
protected ProxyException(string message, Exception innerException) : base(message, innerException) protected ProxyException(string message, Exception? innerException) : base(message, innerException)
{ {
} }
} }
......
...@@ -14,7 +14,7 @@ namespace Titanium.Web.Proxy.Exceptions ...@@ -14,7 +14,7 @@ namespace Titanium.Web.Proxy.Exceptions
/// <param name="message">Message for this exception</param> /// <param name="message">Message for this exception</param>
/// <param name="innerException">Associated inner exception</param> /// <param name="innerException">Associated inner exception</param>
/// <param name="session">Instance of <see cref="EventArguments.SessionEventArgs" /> associated to the exception</param> /// <param name="session">Instance of <see cref="EventArguments.SessionEventArgs" /> associated to the exception</param>
internal ProxyHttpException(string message, Exception? innerException, SessionEventArgs session) : base( internal ProxyHttpException(string message, Exception? innerException, SessionEventArgs? session) : base(
message, innerException) message, innerException)
{ {
Session = session; Session = session;
...@@ -26,6 +26,6 @@ namespace Titanium.Web.Proxy.Exceptions ...@@ -26,6 +26,6 @@ namespace Titanium.Web.Proxy.Exceptions
/// <remarks> /// <remarks>
/// This object properties should not be edited. /// This object properties should not be edited.
/// </remarks> /// </remarks>
public SessionEventArgs Session { get; } public SessionEventArgs? Session { get; }
} }
} }
...@@ -38,16 +38,16 @@ namespace Titanium.Web.Proxy ...@@ -38,16 +38,16 @@ namespace Titanium.Web.Proxy
var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferPool); var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferPool);
var clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool); var clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool);
Task<TcpServerConnection> prefetchConnectionTask = null; Task<TcpServerConnection>? prefetchConnectionTask = null;
bool closeServerConnection = false; bool closeServerConnection = false;
bool calledRequestHandler = false; bool calledRequestHandler = false;
SslStream sslStream = null; SslStream? sslStream = null;
try try
{ {
string connectHostname = null; string? connectHostname = null;
TunnelConnectSessionEventArgs connectArgs = null; TunnelConnectSessionEventArgs? connectArgs = null;
// Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request) // Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
if (await HttpHelper.IsConnectMethod(clientStream, BufferPool, cancellationToken) == 1) if (await HttpHelper.IsConnectMethod(clientStream, BufferPool, cancellationToken) == 1)
...@@ -126,7 +126,7 @@ namespace Titanium.Web.Proxy ...@@ -126,7 +126,7 @@ namespace Titanium.Web.Proxy
var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken); var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken);
bool isClientHello = clientHelloInfo != null; bool isClientHello = clientHelloInfo != null;
if (isClientHello) if (clientHelloInfo != null)
{ {
connectRequest.TunnelType = TunnelType.Https; connectRequest.TunnelType = TunnelType.Https;
connectRequest.ClientHelloInfo = clientHelloInfo; connectRequest.ClientHelloInfo = clientHelloInfo;
...@@ -134,7 +134,7 @@ namespace Titanium.Web.Proxy ...@@ -134,7 +134,7 @@ namespace Titanium.Web.Proxy
await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc, isClientHello); await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc, isClientHello);
if (decryptSsl && isClientHello) if (decryptSsl && clientHelloInfo != null)
{ {
clientConnection.SslProtocol = clientHelloInfo.SslProtocol; clientConnection.SslProtocol = clientHelloInfo.SslProtocol;
connectRequest.RequestUri = new Uri("https://" + httpUrl); connectRequest.RequestUri = new Uri("https://" + httpUrl);
...@@ -166,7 +166,7 @@ namespace Titanium.Web.Proxy ...@@ -166,7 +166,7 @@ namespace Titanium.Web.Proxy
if (EnableTcpServerConnectionPrefetch) if (EnableTcpServerConnectionPrefetch)
{ {
IPAddress[] ipAddresses = null; IPAddress[]? ipAddresses = null;
try try
{ {
// make sure the host can be resolved before creating the prefetch task // make sure the host can be resolved before creating the prefetch task
...@@ -184,7 +184,7 @@ namespace Titanium.Web.Proxy ...@@ -184,7 +184,7 @@ namespace Titanium.Web.Proxy
} }
} }
X509Certificate2 certificate = null; X509Certificate2? certificate = null;
try try
{ {
sslStream = new SslStream(clientStream, false); sslStream = new SslStream(clientStream, false);
...@@ -306,7 +306,7 @@ namespace Titanium.Web.Proxy ...@@ -306,7 +306,7 @@ namespace Titanium.Web.Proxy
string httpCmd = await clientStream.ReadLineAsync(cancellationToken); string httpCmd = await clientStream.ReadLineAsync(cancellationToken);
if (httpCmd == "PRI * HTTP/2.0") if (httpCmd == "PRI * HTTP/2.0")
{ {
connectArgs.HttpClient.ConnectRequest.TunnelType = TunnelType.Http2; connectArgs.HttpClient.ConnectRequest!.TunnelType = TunnelType.Http2;
// HTTP/2 Connection Preface // HTTP/2 Connection Preface
string line = await clientStream.ReadLineAsync(cancellationToken); string line = await clientStream.ReadLineAsync(cancellationToken);
......
...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Extensions
internal static readonly List<SslApplicationProtocol> Http2ProtocolAsList = internal static readonly List<SslApplicationProtocol> Http2ProtocolAsList =
new List<SslApplicationProtocol> { SslApplicationProtocol.Http2 }; new List<SslApplicationProtocol> { SslApplicationProtocol.Http2 };
internal static string GetServerName(this ClientHelloInfo clientHelloInfo) internal static string? GetServerName(this ClientHelloInfo clientHelloInfo)
{ {
if (clientHelloInfo.Extensions != null && if (clientHelloInfo.Extensions != null &&
clientHelloInfo.Extensions.TryGetValue("server_name", out var serverNameExtension)) clientHelloInfo.Extensions.TryGetValue("server_name", out var serverNameExtension))
...@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy.Extensions
} }
#if NETSTANDARD2_1 #if NETSTANDARD2_1
internal static List<SslApplicationProtocol> GetAlpn(this ClientHelloInfo clientHelloInfo) internal static List<SslApplicationProtocol>? GetAlpn(this ClientHelloInfo clientHelloInfo)
{ {
if (clientHelloInfo.Extensions != null && clientHelloInfo.Extensions.TryGetValue("ALPN", out var alpnExtension)) if (clientHelloInfo.Extensions != null && clientHelloInfo.Extensions.TryGetValue("ALPN", out var alpnExtension))
{ {
...@@ -111,7 +111,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -111,7 +111,7 @@ namespace Titanium.Web.Proxy.Extensions
{ {
internal bool AllowRenegotiation { get; set; } internal bool AllowRenegotiation { get; set; }
internal X509Certificate ServerCertificate { get; set; } internal X509Certificate? ServerCertificate { get; set; }
internal bool ClientCertificateRequired { get; set; } internal bool ClientCertificateRequired { get; set; }
...@@ -119,9 +119,9 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -119,9 +119,9 @@ namespace Titanium.Web.Proxy.Extensions
internal X509RevocationMode CertificateRevocationCheckMode { get; set; } internal X509RevocationMode CertificateRevocationCheckMode { get; set; }
internal List<SslApplicationProtocol> ApplicationProtocols { get; set; } internal List<SslApplicationProtocol>? ApplicationProtocols { get; set; }
internal RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; } internal RemoteCertificateValidationCallback? RemoteCertificateValidationCallback { get; set; }
internal EncryptionPolicy EncryptionPolicy { get; set; } internal EncryptionPolicy EncryptionPolicy { get; set; }
} }
......
...@@ -197,7 +197,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -197,7 +197,7 @@ namespace Titanium.Web.Proxy.Helpers
private static async Task<int> startsWith(ICustomStreamReader clientStreamReader, IBufferPool bufferPool, string expectedStart, CancellationToken cancellationToken = default) private static async Task<int> startsWith(ICustomStreamReader clientStreamReader, IBufferPool bufferPool, string expectedStart, CancellationToken cancellationToken = default)
{ {
const int lengthToCheck = 10; const int lengthToCheck = 10;
byte[] buffer = null; byte[]? buffer = null;
try try
{ {
if (bufferPool.BufferSize < lengthToCheck) if (bufferPool.BufferSize < lengthToCheck)
......
...@@ -148,7 +148,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -148,7 +148,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
internal Task CopyBodyAsync(ICustomStreamReader streamReader, bool isChunked, long contentLength, internal Task CopyBodyAsync(ICustomStreamReader streamReader, bool isChunked, long contentLength,
Action<byte[], int, int> onCopy, CancellationToken cancellationToken) Action<byte[], int, int>? onCopy, CancellationToken cancellationToken)
{ {
// For chunked request we need to read data as they arrive, until we reach a chunk end symbol // For chunked request we need to read data as they arrive, until we reach a chunk end symbol
if (isChunked) if (isChunked)
......
...@@ -9,8 +9,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -9,8 +9,8 @@ namespace Titanium.Web.Proxy.Helpers
{ {
internal class ProxyInfo internal class ProxyInfo
{ {
internal ProxyInfo(bool? autoDetect, string autoConfigUrl, int? proxyEnable, string proxyServer, internal ProxyInfo(bool? autoDetect, string? autoConfigUrl, int? proxyEnable, string? proxyServer,
string proxyOverride) string? proxyOverride)
{ {
AutoDetect = autoDetect; AutoDetect = autoDetect;
AutoConfigUrl = autoConfigUrl; AutoConfigUrl = autoConfigUrl;
...@@ -54,13 +54,13 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -54,13 +54,13 @@ namespace Titanium.Web.Proxy.Helpers
internal bool? AutoDetect { get; } internal bool? AutoDetect { get; }
internal string AutoConfigUrl { get; } internal string? AutoConfigUrl { get; }
internal int? ProxyEnable { get; } internal int? ProxyEnable { get; }
internal string ProxyServer { get; } internal string? ProxyServer { get; }
internal string ProxyOverride { get; } internal string? ProxyOverride { get; }
internal bool BypassLoopback { get; } internal bool BypassLoopback { get; }
...@@ -190,7 +190,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -190,7 +190,7 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary> /// </summary>
/// <param name="value"></param> /// <param name="value"></param>
/// <returns></returns> /// <returns></returns>
private static HttpSystemProxyValue parseProxyValue(string value) private static HttpSystemProxyValue? parseProxyValue(string value)
{ {
string tmp = Regex.Replace(value, @"\s+", " ").Trim(); string tmp = Regex.Replace(value, @"\s+", " ").Trim();
......
...@@ -49,7 +49,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -49,7 +49,7 @@ namespace Titanium.Web.Proxy.Helpers
internal const int InternetOptionSettingsChanged = 39; internal const int InternetOptionSettingsChanged = 39;
internal const int InternetOptionRefresh = 37; internal const int InternetOptionRefresh = 37;
private ProxyInfo originalValues; private ProxyInfo? originalValues;
public SystemProxyManager() public SystemProxyManager()
{ {
...@@ -90,8 +90,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -90,8 +90,8 @@ namespace Titanium.Web.Proxy.Helpers
saveOriginalProxyConfiguration(reg); saveOriginalProxyConfiguration(reg);
prepareRegistry(reg); prepareRegistry(reg);
string exisitingContent = reg.GetValue(regProxyServer) as string; string? existingContent = reg.GetValue(regProxyServer) as string;
var existingSystemProxyValues = ProxyInfo.GetSystemProxyValues(exisitingContent); var existingSystemProxyValues = ProxyInfo.GetSystemProxyValues(existingContent);
existingSystemProxyValues.RemoveAll(x => (protocolType & x.ProtocolType) != 0); existingSystemProxyValues.RemoveAll(x => (protocolType & x.ProtocolType) != 0);
if ((protocolType & ProxyProtocolType.Http) != 0) if ((protocolType & ProxyProtocolType.Http) != 0)
{ {
...@@ -141,9 +141,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -141,9 +141,9 @@ namespace Titanium.Web.Proxy.Helpers
if (reg.GetValue(regProxyServer) != null) if (reg.GetValue(regProxyServer) != null)
{ {
string exisitingContent = reg.GetValue(regProxyServer) as string; string? existingContent = reg.GetValue(regProxyServer) as string;
var existingSystemProxyValues = ProxyInfo.GetSystemProxyValues(exisitingContent); var existingSystemProxyValues = ProxyInfo.GetSystemProxyValues(existingContent);
existingSystemProxyValues.RemoveAll(x => (protocolType & x.ProtocolType) != 0); existingSystemProxyValues.RemoveAll(x => (protocolType & x.ProtocolType) != 0);
if (existingSystemProxyValues.Count != 0) if (existingSystemProxyValues.Count != 0)
...@@ -284,7 +284,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -284,7 +284,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
} }
internal ProxyInfo GetProxyInfoFromRegistry() internal ProxyInfo? GetProxyInfoFromRegistry()
{ {
using (var reg = openInternetSettingsKey()) using (var reg = openInternetSettingsKey())
{ {
......
...@@ -103,7 +103,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -103,7 +103,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="exceptionFunc"></param> /// <param name="exceptionFunc"></param>
/// <returns></returns> /// <returns></returns>
private static async Task sendRawTap(Stream clientStream, Stream serverStream, IBufferPool bufferPool, private static async Task sendRawTap(Stream clientStream, Stream serverStream, IBufferPool bufferPool,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, Action<byte[], int, int>? onDataSend, Action<byte[], int, int>? onDataReceive,
CancellationTokenSource cancellationTokenSource, CancellationTokenSource cancellationTokenSource,
ExceptionHandler exceptionFunc) ExceptionHandler exceptionFunc)
{ {
...@@ -133,7 +133,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -133,7 +133,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="exceptionFunc"></param> /// <param name="exceptionFunc"></param>
/// <returns></returns> /// <returns></returns>
internal static Task SendRaw(Stream clientStream, Stream serverStream, IBufferPool bufferPool, internal static Task SendRaw(Stream clientStream, Stream serverStream, IBufferPool bufferPool,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, Action<byte[], int, int>? onDataSend, Action<byte[], int, int>? onDataReceive,
CancellationTokenSource cancellationTokenSource, CancellationTokenSource cancellationTokenSource,
ExceptionHandler exceptionFunc) ExceptionHandler exceptionFunc)
{ {
......
...@@ -13,8 +13,8 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -13,8 +13,8 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
ref WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig); ref WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig);
[DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)] [DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern WinHttpHandle WinHttpOpen(string userAgent, AccessType accessType, string proxyName, internal static extern WinHttpHandle WinHttpOpen(string? userAgent, AccessType accessType, string? proxyName,
string proxyBypass, int dwFlags); string? proxyBypass, int dwFlags);
[DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)] [DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool WinHttpSetTimeouts(WinHttpHandle session, int resolveTimeout, internal static extern bool WinHttpSetTimeouts(WinHttpHandle session, int resolveTimeout,
...@@ -66,7 +66,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -66,7 +66,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
{ {
public AutoProxyFlags Flags; public AutoProxyFlags Flags;
public AutoDetectType AutoDetectFlags; public AutoDetectType AutoDetectFlags;
[MarshalAs(UnmanagedType.LPWStr)] public string AutoConfigUrl; [MarshalAs(UnmanagedType.LPWStr)] public string? AutoConfigUrl;
private readonly IntPtr lpvReserved; private readonly IntPtr lpvReserved;
private readonly int dwReserved; private readonly int dwReserved;
public bool AutoLogonIfChallenged; public bool AutoLogonIfChallenged;
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
...@@ -42,7 +42,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -42,7 +42,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
public bool BypassOnLocal { get; internal set; } public bool BypassOnLocal { get; internal set; }
public Uri AutomaticConfigurationScript { get; internal set; } public Uri? AutomaticConfigurationScript { get; internal set; }
public bool AutomaticallyDetectSettings { get; internal set; } public bool AutomaticallyDetectSettings { get; internal set; }
...@@ -53,7 +53,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -53,7 +53,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
dispose(true); dispose(true);
} }
public bool GetAutoProxies(Uri destination, out IList<string> proxyList) public bool GetAutoProxies(Uri destination, out IList<string>? proxyList)
{ {
proxyList = null; proxyList = null;
if (session == null || session.IsInvalid || state == AutoWebProxyState.UnrecognizedScheme) if (session == null || session.IsInvalid || state == AutoWebProxyState.UnrecognizedScheme)
...@@ -61,7 +61,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -61,7 +61,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
return false; return false;
} }
string proxyListString = null; string? proxyListString = null;
var errorCode = NativeMethods.WinHttp.ErrorCodes.AudodetectionFailed; var errorCode = NativeMethods.WinHttp.ErrorCodes.AudodetectionFailed;
if (AutomaticallyDetectSettings && !autoDetectFailed) if (AutomaticallyDetectSettings && !autoDetectFailed)
{ {
...@@ -88,14 +88,14 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -88,14 +88,14 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
if (!string.IsNullOrEmpty(proxyListString)) if (!string.IsNullOrEmpty(proxyListString))
{ {
proxyListString = removeWhitespaces(proxyListString); proxyListString = removeWhitespaces(proxyListString!);
proxyList = proxyListString.Split(';'); proxyList = proxyListString.Split(';');
} }
return true; return true;
} }
public ExternalProxy GetProxy(Uri destination) public ExternalProxy? GetProxy(Uri destination)
{ {
if (GetAutoProxies(destination, out var proxies)) if (GetAutoProxies(destination, out var proxies))
{ {
...@@ -131,12 +131,12 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -131,12 +131,12 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
var protocolType = ProxyInfo.ParseProtocolType(destination.Scheme); var protocolType = ProxyInfo.ParseProtocolType(destination.Scheme);
if (protocolType.HasValue) if (protocolType.HasValue)
{ {
HttpSystemProxyValue value = null; HttpSystemProxyValue? value = null;
if (ProxyInfo?.Proxies?.TryGetValue(protocolType.Value, out value) == true) if (ProxyInfo?.Proxies?.TryGetValue(protocolType.Value, out value) == true)
{ {
var systemProxy = new ExternalProxy var systemProxy = new ExternalProxy
{ {
HostName = value.HostName, HostName = value!.HostName,
Port = value.Port Port = value.Port
}; };
...@@ -210,7 +210,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -210,7 +210,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
session.Close(); session.Close();
} }
private int getAutoProxies(Uri destination, Uri scriptLocation, out string proxyListString) private int getAutoProxies(Uri destination, Uri? scriptLocation, out string? proxyListString)
{ {
int num = 0; int num = 0;
var autoProxyOptions = new NativeMethods.WinHttp.WINHTTP_AUTOPROXY_OPTIONS(); var autoProxyOptions = new NativeMethods.WinHttp.WINHTTP_AUTOPROXY_OPTIONS();
...@@ -247,7 +247,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -247,7 +247,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
} }
private bool winHttpGetProxyForUrl(string destination, private bool winHttpGetProxyForUrl(string destination,
ref NativeMethods.WinHttp.WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions, out string proxyListString) ref NativeMethods.WinHttp.WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions, out string? proxyListString)
{ {
proxyListString = null; proxyListString = null;
bool flag; bool flag;
......
...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Http
/// </summary> /// </summary>
public class ConnectResponse : Response public class ConnectResponse : Response
{ {
public ServerHelloInfo ServerHelloInfo { get; set; } public ServerHelloInfo? ServerHelloInfo { get; set; }
/// <summary> /// <summary>
/// Creates a successful CONNECT response /// Creates a successful CONNECT response
......
...@@ -71,7 +71,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -71,7 +71,7 @@ namespace Titanium.Web.Proxy.Http
/// </summary> /// </summary>
/// <param name="name"></param> /// <param name="name"></param>
/// <returns></returns> /// <returns></returns>
public List<HttpHeader> GetHeaders(string name) public List<HttpHeader>? GetHeaders(string name)
{ {
if (headers.ContainsKey(name)) if (headers.ContainsKey(name))
{ {
...@@ -89,7 +89,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -89,7 +89,7 @@ namespace Titanium.Web.Proxy.Http
return null; return null;
} }
public HttpHeader GetFirstHeader(string name) public HttpHeader? GetFirstHeader(string name)
{ {
if (headers.TryGetValue(name, out var header)) if (headers.TryGetValue(name, out var header))
{ {
...@@ -198,7 +198,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -198,7 +198,7 @@ namespace Titanium.Web.Proxy.Http
/// Adds the given header objects to Request /// Adds the given header objects to Request
/// </summary> /// </summary>
/// <param name="newHeaders"></param> /// <param name="newHeaders"></param>
public void AddHeaders(IEnumerable<KeyValuePair<string, HttpHeader>> newHeaders) public void AddHeaders(IEnumerable<KeyValuePair<string, HttpHeader>>? newHeaders)
{ {
if (newHeaders == null) if (newHeaders == null)
{ {
...@@ -272,7 +272,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -272,7 +272,7 @@ namespace Titanium.Web.Proxy.Http
nonUniqueHeaders.Clear(); nonUniqueHeaders.Clear();
} }
internal string GetHeaderValueOrNull(string headerName) internal string? GetHeaderValueOrNull(string headerName)
{ {
if (headers.TryGetValue(headerName, out var header)) if (headers.TryGetValue(headerName, out var header))
{ {
...@@ -282,8 +282,14 @@ namespace Titanium.Web.Proxy.Http ...@@ -282,8 +282,14 @@ namespace Titanium.Web.Proxy.Http
return null; return null;
} }
internal void SetOrAddHeaderValue(string headerName, string value) internal void SetOrAddHeaderValue(string headerName, string? value)
{ {
if (value == null)
{
RemoveHeader(headerName);
return;
}
if (headers.TryGetValue(headerName, out var header)) if (headers.TryGetValue(headerName, out var header))
{ {
header.Value = value; header.Value = value;
...@@ -300,7 +306,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -300,7 +306,7 @@ namespace Titanium.Web.Proxy.Http
internal void FixProxyHeaders() internal void FixProxyHeaders()
{ {
// If proxy-connection close was returned inform to close the connection // If proxy-connection close was returned inform to close the connection
string proxyHeader = GetHeaderValueOrNull(KnownHeaders.ProxyConnection); string? proxyHeader = GetHeaderValueOrNull(KnownHeaders.ProxyConnection);
RemoveHeader(KnownHeaders.ProxyConnection); RemoveHeader(KnownHeaders.ProxyConnection);
if (proxyHeader != null) if (proxyHeader != null)
......
...@@ -17,6 +17,8 @@ namespace Titanium.Web.Proxy.Http ...@@ -17,6 +17,8 @@ namespace Titanium.Web.Proxy.Http
/// </summary> /// </summary>
public class HttpWebClient public class HttpWebClient
{ {
private TcpServerConnection? connection;
internal HttpWebClient(Request? request) internal HttpWebClient(Request? request)
{ {
Request = request ?? new Request(); Request = request ?? new Request();
...@@ -26,7 +28,20 @@ namespace Titanium.Web.Proxy.Http ...@@ -26,7 +28,20 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Connection to server /// Connection to server
/// </summary> /// </summary>
internal TcpServerConnection Connection { get; set; } internal TcpServerConnection Connection
{
get
{
if (connection == null)
{
throw new Exception("Connection is null");
}
return connection;
}
}
internal bool HasConnection => connection != null;
/// <summary> /// <summary>
/// Should we close the server connection at the end of this HTTP request/response session. /// Should we close the server connection at the end of this HTTP request/response session.
...@@ -41,7 +56,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -41,7 +56,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Gets or sets the user data. /// Gets or sets the user data.
/// </summary> /// </summary>
public object UserData { get; set; } public object? UserData { get; set; }
/// <summary> /// <summary>
/// Override UpStreamEndPoint for this request; Local NIC via request is made /// Override UpStreamEndPoint for this request; Local NIC via request is made
...@@ -51,7 +66,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -51,7 +66,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Headers passed with Connect. /// Headers passed with Connect.
/// </summary> /// </summary>
public ConnectRequest ConnectRequest { get; internal set; } public ConnectRequest? ConnectRequest { get; internal set; }
/// <summary> /// <summary>
/// Web Request. /// Web Request.
...@@ -81,7 +96,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -81,7 +96,7 @@ namespace Titanium.Web.Proxy.Http
internal void SetConnection(TcpServerConnection serverConnection) internal void SetConnection(TcpServerConnection serverConnection)
{ {
serverConnection.LastAccess = DateTime.Now; serverConnection.LastAccess = DateTime.Now;
Connection = serverConnection; connection = serverConnection;
} }
/// <summary> /// <summary>
...@@ -199,7 +214,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -199,7 +214,7 @@ namespace Titanium.Web.Proxy.Http
/// </summary> /// </summary>
internal void FinishSession() internal void FinishSession()
{ {
Connection = null; connection = null;
ConnectRequest?.FinishSession(); ConnectRequest?.FinishSession();
Request?.FinishSession(); Request?.FinishSession();
......
using System.Collections.Generic; using System.Collections.Generic;
namespace Titanium.Web.Proxy.Http namespace Titanium.Web.Proxy.Http
{ {
...@@ -13,7 +13,8 @@ namespace Titanium.Web.Proxy.Http ...@@ -13,7 +13,8 @@ namespace Titanium.Web.Proxy.Http
} }
else else
{ {
value = default; // hack: https://stackoverflow.com/questions/54593923/nullable-reference-types-with-generic-return-type
value = default!;
} }
return result; return result;
......
...@@ -86,7 +86,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -86,7 +86,7 @@ namespace Titanium.Web.Proxy.Http
/// Note: Changing this does NOT change host in RequestUri. /// Note: Changing this does NOT change host in RequestUri.
/// Users can set new RequestUri separately. /// Users can set new RequestUri separately.
/// </summary> /// </summary>
public string Host public string? Host
{ {
get => Headers.GetHeaderValueOrNull(KnownHeaders.Host); get => Headers.GetHeaderValueOrNull(KnownHeaders.Host);
set => Headers.SetOrAddHeaderValue(KnownHeaders.Host, value); set => Headers.SetOrAddHeaderValue(KnownHeaders.Host, value);
...@@ -99,7 +99,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -99,7 +99,7 @@ namespace Titanium.Web.Proxy.Http
{ {
get get
{ {
string headerValue = Headers.GetHeaderValueOrNull(KnownHeaders.Expect); string? headerValue = Headers.GetHeaderValueOrNull(KnownHeaders.Expect);
return headerValue != null && headerValue.Equals(KnownHeaders.Expect100Continue); return headerValue != null && headerValue.Equals(KnownHeaders.Expect100Continue);
} }
} }
...@@ -127,7 +127,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -127,7 +127,7 @@ namespace Titanium.Web.Proxy.Http
{ {
get get
{ {
string headerValue = Headers.GetHeaderValueOrNull(KnownHeaders.Upgrade); string? headerValue = Headers.GetHeaderValueOrNull(KnownHeaders.Upgrade);
if (headerValue == null) if (headerValue == null)
{ {
......
...@@ -19,12 +19,12 @@ namespace Titanium.Web.Proxy.Http ...@@ -19,12 +19,12 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Cached body content as byte array. /// Cached body content as byte array.
/// </summary> /// </summary>
protected byte[] BodyInternal { get; private set; } protected byte[]? BodyInternal { get; private set; }
/// <summary> /// <summary>
/// Cached body as string. /// Cached body as string.
/// </summary> /// </summary>
private string bodyString; private string? bodyString;
/// <summary> /// <summary>
/// Store whether the original request/response has body or not, since the user may change the parameters. /// Store whether the original request/response has body or not, since the user may change the parameters.
...@@ -48,13 +48,13 @@ namespace Titanium.Web.Proxy.Http ...@@ -48,13 +48,13 @@ namespace Titanium.Web.Proxy.Http
/// Store whether the original request/response content-encoding, since the user may change the parameters. /// Store whether the original request/response content-encoding, since the user may change the parameters.
/// We need this detail to syphon out attached tcp connection for reuse. /// We need this detail to syphon out attached tcp connection for reuse.
/// </summary> /// </summary>
internal string OriginalContentEncoding { get; set; } internal string? OriginalContentEncoding { get; set; }
internal TaskCompletionSource<bool> ReadHttp2BeforeHandlerTaskCompletionSource; internal TaskCompletionSource<bool>? ReadHttp2BeforeHandlerTaskCompletionSource;
internal TaskCompletionSource<bool> ReadHttp2BodyTaskCompletionSource; internal TaskCompletionSource<bool>? ReadHttp2BodyTaskCompletionSource;
internal MemoryStream Http2BodyData; internal MemoryStream? Http2BodyData;
internal bool Http2IgnoreBodyFrames; internal bool Http2IgnoreBodyFrames;
...@@ -87,7 +87,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -87,7 +87,7 @@ namespace Titanium.Web.Proxy.Http
{ {
get get
{ {
string headerValue = Headers.GetHeaderValueOrNull(KnownHeaders.ContentLength); string? headerValue = Headers.GetHeaderValueOrNull(KnownHeaders.ContentLength);
if (headerValue == null) if (headerValue == null)
{ {
...@@ -119,7 +119,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -119,7 +119,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Content encoding for this request/response. /// Content encoding for this request/response.
/// </summary> /// </summary>
public string ContentEncoding => Headers.GetHeaderValueOrNull(KnownHeaders.ContentEncoding)?.Trim(); public string? ContentEncoding => Headers.GetHeaderValueOrNull(KnownHeaders.ContentEncoding)?.Trim();
/// <summary> /// <summary>
/// Encoding for this request/response. /// Encoding for this request/response.
...@@ -129,7 +129,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -129,7 +129,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Content-type of the request/response. /// Content-type of the request/response.
/// </summary> /// </summary>
public string ContentType public string? ContentType
{ {
get => Headers.GetHeaderValueOrNull(KnownHeaders.ContentType); get => Headers.GetHeaderValueOrNull(KnownHeaders.ContentType);
set => Headers.SetOrAddHeaderValue(KnownHeaders.ContentType, value); set => Headers.SetOrAddHeaderValue(KnownHeaders.ContentType, value);
...@@ -142,7 +142,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -142,7 +142,7 @@ namespace Titanium.Web.Proxy.Http
{ {
get get
{ {
string headerValue = Headers.GetHeaderValueOrNull(KnownHeaders.TransferEncoding); string? headerValue = Headers.GetHeaderValueOrNull(KnownHeaders.TransferEncoding);
return headerValue != null && headerValue.ContainsIgnoreCase(KnownHeaders.TransferEncodingChunked); return headerValue != null && headerValue.ContainsIgnoreCase(KnownHeaders.TransferEncodingChunked);
} }
...@@ -174,7 +174,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -174,7 +174,7 @@ namespace Titanium.Web.Proxy.Http
get get
{ {
EnsureBodyAvailable(); EnsureBodyAvailable();
return BodyInternal; return BodyInternal!;
} }
internal set internal set
...@@ -233,7 +233,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -233,7 +233,7 @@ namespace Titanium.Web.Proxy.Http
} }
} }
internal byte[] CompressBodyAndUpdateContentLength() internal byte[]? CompressBodyAndUpdateContentLength()
{ {
if (!IsBodyRead && BodyInternal == null) if (!IsBodyRead && BodyInternal == null)
{ {
...@@ -241,7 +241,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -241,7 +241,7 @@ namespace Titanium.Web.Proxy.Http
} }
bool isChunked = IsChunked; bool isChunked = IsChunked;
string contentEncoding = ContentEncoding; string? contentEncoding = ContentEncoding;
if (HasBody) if (HasBody)
{ {
......
...@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy.Http
{ {
get get
{ {
string headerValue = Headers.GetHeaderValueOrNull(KnownHeaders.Connection); string? headerValue = Headers.GetHeaderValueOrNull(KnownHeaders.Connection);
if (headerValue != null) if (headerValue != null)
{ {
......
...@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy.Http.Responses ...@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy.Http.Responses
StatusDescription = statusDescription; StatusDescription = statusDescription;
} }
internal static string Get(int code) internal static string? Get(int code)
{ {
switch (code) switch (code)
{ {
......
...@@ -519,16 +519,15 @@ namespace Titanium.Web.Proxy.Http2.Hpack ...@@ -519,16 +519,15 @@ namespace Titanium.Web.Proxy.Http2.Hpack
var headerField = StaticTable.Get(index); var headerField = StaticTable.Get(index);
return headerField; return headerField;
} }
else if (index - StaticTable.Length <= dynamicTable.Length())
if (index - StaticTable.Length <= dynamicTable.Length())
{ {
var headerField = dynamicTable.GetEntry(index - StaticTable.Length); var headerField = dynamicTable.GetEntry(index - StaticTable.Length);
return headerField; return headerField;
} }
else
{
throw new IOException("illegal index value (" + index + ")"); throw new IOException("illegal index value (" + index + ")");
} }
}
private void ReadName(int index) private void ReadName(int index)
{ {
......
...@@ -23,7 +23,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack ...@@ -23,7 +23,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
public class DynamicTable public class DynamicTable
{ {
// a circular queue of header fields // a circular queue of header fields
HttpHeader[] headerFields; HttpHeader?[] headerFields;
int head; int head;
int tail; int tail;
...@@ -89,10 +89,10 @@ namespace Titanium.Web.Proxy.Http2.Hpack ...@@ -89,10 +89,10 @@ namespace Titanium.Web.Proxy.Http2.Hpack
int i = head - index; int i = head - index;
if (i < 0) if (i < 0)
{ {
return headerFields[i + headerFields.Length]; return headerFields[i + headerFields.Length]!;
} }
return headerFields[i]; return headerFields[i]!;
} }
/// <summary> /// <summary>
...@@ -128,7 +128,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack ...@@ -128,7 +128,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
/// <summary> /// <summary>
/// Remove and return the oldest header field from the dynamic table. /// Remove and return the oldest header field from the dynamic table.
/// </summary> /// </summary>
public HttpHeader Remove() public HttpHeader? Remove()
{ {
var removed = headerFields[tail]; var removed = headerFields[tail];
if (removed == null) if (removed == null)
...@@ -218,8 +218,8 @@ namespace Titanium.Web.Proxy.Http2.Hpack ...@@ -218,8 +218,8 @@ namespace Titanium.Web.Proxy.Http2.Hpack
int cursor = tail; int cursor = tail;
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
{ {
var entry = headerFields[cursor++]; var entry = headerFields![cursor++];
tmp[i] = entry; tmp[i] = entry!;
if (cursor == headerFields.Length) if (cursor == headerFields.Length)
{ {
cursor = 0; cursor = 0;
......
...@@ -27,7 +27,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack ...@@ -27,7 +27,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
private const int bucketSize = 17; private const int bucketSize = 17;
// a linked hash map of header fields // a linked hash map of header fields
private readonly HeaderEntry[] headerFields = new HeaderEntry[bucketSize]; private readonly HeaderEntry?[] headerFields = new HeaderEntry[bucketSize];
private readonly HeaderEntry head = new HeaderEntry(-1, string.Empty, string.Empty, int.MaxValue, null); private readonly HeaderEntry head = new HeaderEntry(-1, string.Empty, string.Empty, int.MaxValue, null);
private int size; private int size;
...@@ -299,7 +299,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack ...@@ -299,7 +299,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
/// <returns>The entry.</returns> /// <returns>The entry.</returns>
/// <param name="name">Name.</param> /// <param name="name">Name.</param>
/// <param name="value">Value.</param> /// <param name="value">Value.</param>
private HeaderEntry getEntry(string name, string value) private HeaderEntry? getEntry(string name, string value)
{ {
if (length() == 0 || name == null || value == null) if (length() == 0 || name == null || value == null)
{ {
...@@ -400,7 +400,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack ...@@ -400,7 +400,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
/// <summary> /// <summary>
/// Remove and return the oldest header field from the dynamic table. /// Remove and return the oldest header field from the dynamic table.
/// </summary> /// </summary>
private HttpHeader remove() private HttpHeader? remove()
{ {
if (size == 0) if (size == 0)
{ {
...@@ -423,7 +423,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack ...@@ -423,7 +423,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
} }
else else
{ {
prev.Next = next; prev!.Next = next;
} }
eldest.Remove(); eldest.Remove();
...@@ -500,7 +500,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack ...@@ -500,7 +500,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
public HeaderEntry After { get; set; } public HeaderEntry After { get; set; }
// These fields comprise the chained list for header fields with the same hash. // These fields comprise the chained list for header fields with the same hash.
public HeaderEntry Next { get; set; } public HeaderEntry? Next { get; set; }
public int Hash { get; } public int Hash { get; }
...@@ -514,7 +514,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack ...@@ -514,7 +514,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
/// <param name="value">Value.</param> /// <param name="value">Value.</param>
/// <param name="index">Index.</param> /// <param name="index">Index.</param>
/// <param name="next">Next.</param> /// <param name="next">Next.</param>
public HeaderEntry(int hash, string name, string value, int index, HeaderEntry next) : base(name, value, true) public HeaderEntry(int hash, string name, string value, int index, HeaderEntry? next) : base(name, value, true)
{ {
Index = index; Index = index;
Hash = hash; Hash = hash;
......
...@@ -69,7 +69,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack ...@@ -69,7 +69,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
while (bits >= 8) while (bits >= 8)
{ {
int c = (current >> (bits - 8)) & 0xFF; int c = (current >> (bits - 8)) & 0xFF;
node = node.Children[c]; node = node.Children![c];
bits -= node.Bits; bits -= node.Bits;
if (node.IsTerminal) if (node.IsTerminal)
{ {
...@@ -87,7 +87,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack ...@@ -87,7 +87,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
while (bits > 0) while (bits > 0)
{ {
int c = (current << (8 - bits)) & 0xFF; int c = (current << (8 - bits)) & 0xFF;
node = node.Children[c]; node = node.Children![c];
if (node.IsTerminal && node.Bits <= bits) if (node.IsTerminal && node.Bits <= bits)
{ {
bits -= node.Bits; bits -= node.Bits;
...@@ -121,7 +121,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack ...@@ -121,7 +121,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
public int Bits { get; } public int Bits { get; }
// internal nodes have children // internal nodes have children
public Node[] Children { get; } public Node[]? Children { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HuffmanDecoder"/> class. /// Initializes a new instance of the <see cref="HuffmanDecoder"/> class.
...@@ -173,7 +173,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack ...@@ -173,7 +173,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
length -= 8; length -= 8;
int i = (code >> length) & 0xFF; int i = (code >> length) & 0xFF;
if (current.Children[i] == null) if (current.Children![i] == null)
{ {
current.Children[i] = new Node(); current.Children[i] = new Node();
} }
...@@ -187,7 +187,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack ...@@ -187,7 +187,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
int end = 1 << shift; int end = 1 << shift;
for (int i = start; i < start + end; i++) for (int i = start; i < start + end; i++)
{ {
current.Children[i] = terminal; current.Children![i] = terminal;
} }
} }
} }
......
...@@ -59,11 +59,11 @@ namespace Titanium.Web.Proxy.Http2 ...@@ -59,11 +59,11 @@ namespace Titanium.Web.Proxy.Http2
ExceptionHandler exceptionFunc) ExceptionHandler exceptionFunc)
{ {
int headerTableSize = 0; int headerTableSize = 0;
Decoder decoder = null; Decoder? decoder = null;
var frameHeader = new Http2FrameHeader(); var frameHeader = new Http2FrameHeader();
frameHeader.Buffer = new byte[9]; frameHeader.Buffer = new byte[9];
byte[] buffer = null; byte[]? buffer = null;
while (true) while (true)
{ {
var frameHeaderBuffer = frameHeader.Buffer; var frameHeaderBuffer = frameHeader.Buffer;
...@@ -98,8 +98,8 @@ namespace Titanium.Web.Proxy.Http2 ...@@ -98,8 +98,8 @@ namespace Titanium.Web.Proxy.Http2
bool sendPacket = true; bool sendPacket = true;
bool endStream = false; bool endStream = false;
SessionEventArgs args = null; SessionEventArgs? args = null;
RequestResponseBase rr = null; RequestResponseBase? rr = null;
if (type == Http2FrameType.Data || type == Http2FrameType.Headers/* || type == Http2FrameType.PushPromise*/) if (type == Http2FrameType.Data || type == Http2FrameType.Headers/* || type == Http2FrameType.PushPromise*/)
{ {
if (!sessions.TryGetValue(streamId, out args)) if (!sessions.TryGetValue(streamId, out args))
...@@ -156,7 +156,7 @@ namespace Titanium.Web.Proxy.Http2 ...@@ -156,7 +156,7 @@ namespace Titanium.Web.Proxy.Http2
length -= buffer[0]; length -= buffer[0];
} }
data.Write(buffer, offset, length); data!.Write(buffer, offset, length);
} }
} }
else if (type == Http2FrameType.Headers/* || type == Http2FrameType.PushPromise*/) else if (type == Http2FrameType.Headers/* || type == Http2FrameType.PushPromise*/)
...@@ -247,9 +247,16 @@ namespace Titanium.Web.Proxy.Http2 ...@@ -247,9 +247,16 @@ namespace Titanium.Web.Proxy.Http2
if (rr is Request request) if (rr is Request request)
{ {
string? method = headerListener.Method;
string? path = headerListener.Path;
if (method == null || path == null)
{
throw new Exception("HTTP/2 Missing method or path");
}
request.HttpVersion = HttpVersion.Version20; request.HttpVersion = HttpVersion.Version20;
request.Method = headerListener.Method; request.Method = method;
request.OriginalUrl = headerListener.Path; request.OriginalUrl = path;
request.RequestUri = headerListener.GetUri(); request.RequestUri = headerListener.GetUri();
} }
...@@ -349,12 +356,12 @@ namespace Titanium.Web.Proxy.Http2 ...@@ -349,12 +356,12 @@ namespace Titanium.Web.Proxy.Http2
} }
} }
if (endStream && rr.ReadHttp2BodyTaskCompletionSource != null) if (endStream && rr!.ReadHttp2BodyTaskCompletionSource != null)
{ {
if (!rr.BodyAvailable) if (!rr.BodyAvailable)
{ {
var data = rr.Http2BodyData; var data = rr.Http2BodyData;
var body = data.ToArray(); var body = data!.ToArray();
if (rr.ContentEncoding != null) if (rr.ContentEncoding != null)
{ {
...@@ -390,7 +397,7 @@ namespace Titanium.Web.Proxy.Http2 ...@@ -390,7 +397,7 @@ namespace Titanium.Web.Proxy.Http2
await rr.Http2BeforeHandlerTask; await rr.Http2BeforeHandlerTask;
} }
if (args.IsPromise) if (args!.IsPromise)
{ {
breakpoint(); breakpoint();
} }
...@@ -502,7 +509,7 @@ namespace Titanium.Web.Proxy.Http2 ...@@ -502,7 +509,7 @@ namespace Titanium.Web.Proxy.Http2
if (rr.HasBody && rr.IsBodyRead) if (rr.HasBody && rr.IsBodyRead)
{ {
int pos = 0; int pos = 0;
while (pos < body.Length) while (pos < body!.Length)
{ {
int bodyFrameLength = Math.Min(buffer.Length, body.Length - pos); int bodyFrameLength = Math.Min(buffer.Length, body.Length - pos);
Buffer.BlockCopy(body, pos, buffer, 0, bodyFrameLength); Buffer.BlockCopy(body, pos, buffer, 0, bodyFrameLength);
...@@ -555,15 +562,15 @@ namespace Titanium.Web.Proxy.Http2 ...@@ -555,15 +562,15 @@ namespace Titanium.Web.Proxy.Http2
{ {
private readonly Action<string, string> addHeaderFunc; private readonly Action<string, string> addHeaderFunc;
public string Method { get; private set; } public string? Method { get; private set; }
public string Status { get; private set; } public string? Status { get; private set; }
private string authority; private string? authority;
private string scheme; private string? scheme;
public string Path { get; private set; } public string? Path { get; private set; }
public MyHeaderListener(Action<string, string> addHeaderFunc) public MyHeaderListener(Action<string, string> addHeaderFunc)
{ {
......
...@@ -33,13 +33,13 @@ namespace Titanium.Web.Proxy.Models ...@@ -33,13 +33,13 @@ namespace Titanium.Web.Proxy.Models
/// Set the <see cref="TunnelConnectSessionEventArgs.DecryptSsl" /> property to false if this HTTP connect request /// Set the <see cref="TunnelConnectSessionEventArgs.DecryptSsl" /> property to false if this HTTP connect request
/// shouldn't be decrypted and instead be relayed. /// shouldn't be decrypted and instead be relayed.
/// </summary> /// </summary>
public event AsyncEventHandler<TunnelConnectSessionEventArgs> BeforeTunnelConnectRequest; public event AsyncEventHandler<TunnelConnectSessionEventArgs>? BeforeTunnelConnectRequest;
/// <summary> /// <summary>
/// Intercept tunnel connect response. /// Intercept tunnel connect response.
/// Valid only for explicit endpoints. /// Valid only for explicit endpoints.
/// </summary> /// </summary>
public event AsyncEventHandler<TunnelConnectSessionEventArgs> BeforeTunnelConnectResponse; public event AsyncEventHandler<TunnelConnectSessionEventArgs>? BeforeTunnelConnectResponse;
internal async Task InvokeBeforeTunnelConnectRequest(ProxyServer proxyServer, internal async Task InvokeBeforeTunnelConnectRequest(ProxyServer proxyServer,
TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc) TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc)
......
using System; using System;
using System.Net;
using System.Text; using System.Text;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
...@@ -16,13 +17,21 @@ namespace Titanium.Web.Proxy.Models ...@@ -16,13 +17,21 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public const int HttpHeaderOverhead = 32; public const int HttpHeaderOverhead = 32;
internal static readonly Version VersionUnknown = new Version(0, 0); #if NETSTANDARD2_1
internal static Version VersionUnknown => HttpVersion.Unknown;
#else
internal static Version VersionUnknown { get; } = new Version(0, 0);
#endif
internal static readonly Version Version10 = new Version(1, 0); internal static Version Version10 => HttpVersion.Version10;
internal static readonly Version Version11 = new Version(1, 1); internal static Version Version11 => HttpVersion.Version11;
internal static readonly Version Version20 = new Version(2, 0); #if NETSTANDARD2_1
internal static Version Version20 => HttpVersion.Version20;
#else
internal static Version Version20 { get; } = new Version(2, 0);
#endif
internal static readonly HttpHeader ProxyConnectionKeepAlive = new HttpHeader("Proxy-Connection", "keep-alive"); internal static readonly HttpHeader ProxyConnectionKeepAlive = new HttpHeader("Proxy-Connection", "keep-alive");
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
/// <summary> /// <summary>
/// An optional continuation token to return to the caller if set /// An optional continuation token to return to the caller if set
/// </summary> /// </summary>
public string Continuation { get; set; } public string? Continuation { get; set; }
public static ProxyAuthenticationContext Failed() public static ProxyAuthenticationContext Failed()
{ {
......
...@@ -32,7 +32,7 @@ namespace Titanium.Web.Proxy.Models ...@@ -32,7 +32,7 @@ namespace Titanium.Web.Proxy.Models
/// <summary> /// <summary>
/// Before Ssl authentication this event is fired. /// Before Ssl authentication this event is fired.
/// </summary> /// </summary>
public event AsyncEventHandler<BeforeSslAuthenticateEventArgs> BeforeSslAuthenticate; public event AsyncEventHandler<BeforeSslAuthenticateEventArgs>? BeforeSslAuthenticate;
internal async Task InvokeBeforeSslAuthenticate(ProxyServer proxyServer, internal async Task InvokeBeforeSslAuthenticate(ProxyServer proxyServer,
BeforeSslAuthenticateEventArgs connectArgs, ExceptionHandler exceptionFunc) BeforeSslAuthenticateEventArgs connectArgs, ExceptionHandler exceptionFunc)
......
...@@ -48,9 +48,9 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -48,9 +48,9 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <param name="isRoot">if set to <c>true</c> [is root].</param> /// <param name="isRoot">if set to <c>true</c> [is root].</param>
/// <param name="signingCert">The signing cert.</param> /// <param name="signingCert">The signing cert.</param>
/// <returns>X509Certificate2 instance.</returns> /// <returns>X509Certificate2 instance.</returns>
public X509Certificate2 MakeCertificate(string sSubjectCn, bool isRoot, X509Certificate2 signingCert = null) public X509Certificate2 MakeCertificate(string sSubjectCn, X509Certificate2? signingCert = null)
{ {
return makeCertificateInternal(sSubjectCn, isRoot, true, signingCert); return makeCertificateInternal(sSubjectCn, true, signingCert);
} }
/// <summary> /// <summary>
...@@ -66,12 +66,12 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -66,12 +66,12 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <param name="hostName">The host name</param> /// <param name="hostName">The host name</param>
/// <returns>X509Certificate2 instance.</returns> /// <returns>X509Certificate2 instance.</returns>
/// <exception cref="PemException">Malformed sequence in RSA private key</exception> /// <exception cref="PemException">Malformed sequence in RSA private key</exception>
private static X509Certificate2 generateCertificate(string hostName, private static X509Certificate2 generateCertificate(string? hostName,
string subjectName, string subjectName,
string issuerName, DateTime validFrom, string issuerName, DateTime validFrom,
DateTime validTo, int keyStrength = 2048, DateTime validTo, int keyStrength = 2048,
string signatureAlgorithm = "SHA256WithRSA", string signatureAlgorithm = "SHA256WithRSA",
AsymmetricKeyParameter issuerPrivateKey = null) AsymmetricKeyParameter? issuerPrivateKey = null)
{ {
// Generating Random Numbers // Generating Random Numbers
var randomGenerator = new CryptoApiRandomGenerator(); var randomGenerator = new CryptoApiRandomGenerator();
...@@ -162,11 +162,11 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -162,11 +162,11 @@ namespace Titanium.Web.Proxy.Network.Certificate
private static X509Certificate2 withPrivateKey(X509Certificate certificate, AsymmetricKeyParameter privateKey) private static X509Certificate2 withPrivateKey(X509Certificate certificate, AsymmetricKeyParameter privateKey)
{ {
const string password = "password"; const string password = "password";
Pkcs12Store store = null; Pkcs12Store store;
if(RunTime.IsRunningOnMono) if(RunTime.IsRunningOnMono)
{ {
Pkcs12StoreBuilder builder = new Pkcs12StoreBuilder(); var builder = new Pkcs12StoreBuilder();
builder.SetUseDerEncoding(true); builder.SetUseDerEncoding(true);
store = builder.Build(); store = builder.Build();
} }
...@@ -190,7 +190,6 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -190,7 +190,6 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <summary> /// <summary>
/// Makes the certificate internal. /// Makes the certificate internal.
/// </summary> /// </summary>
/// <param name="isRoot">if set to <c>true</c> [is root].</param>
/// <param name="hostName">hostname for certificate</param> /// <param name="hostName">hostname for certificate</param>
/// <param name="subjectName">The full subject.</param> /// <param name="subjectName">The full subject.</param>
/// <param name="validFrom">The valid from.</param> /// <param name="validFrom">The valid from.</param>
...@@ -201,18 +200,10 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -201,18 +200,10 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// You must specify a Signing Certificate if and only if you are not creating a /// You must specify a Signing Certificate if and only if you are not creating a
/// root. /// root.
/// </exception> /// </exception>
private X509Certificate2 makeCertificateInternal(bool isRoot, private X509Certificate2 makeCertificateInternal(string hostName, string subjectName,
string hostName, string subjectName, DateTime validFrom, DateTime validTo, X509Certificate2? signingCertificate)
DateTime validFrom, DateTime validTo, X509Certificate2 signingCertificate)
{ {
if (isRoot != (null == signingCertificate)) if (signingCertificate == null)
{
throw new ArgumentException(
"You must specify a Signing Certificate if and only if you are not creating a root.",
nameof(signingCertificate));
}
if (isRoot)
{ {
return generateCertificate(null, subjectName, subjectName, validFrom, validTo); return generateCertificate(null, subjectName, subjectName, validFrom, validTo);
} }
...@@ -226,18 +217,17 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -226,18 +217,17 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// Makes the certificate internal. /// Makes the certificate internal.
/// </summary> /// </summary>
/// <param name="subject">The s subject cn.</param> /// <param name="subject">The s subject cn.</param>
/// <param name="isRoot">if set to <c>true</c> [is root].</param>
/// <param name="switchToMtaIfNeeded">if set to <c>true</c> [switch to MTA if needed].</param> /// <param name="switchToMtaIfNeeded">if set to <c>true</c> [switch to MTA if needed].</param>
/// <param name="signingCert">The signing cert.</param> /// <param name="signingCert">The signing cert.</param>
/// <param name="cancellationToken">Task cancellation token</param> /// <param name="cancellationToken">Task cancellation token</param>
/// <returns>X509Certificate2.</returns> /// <returns>X509Certificate2.</returns>
private X509Certificate2 makeCertificateInternal(string subject, bool isRoot, private X509Certificate2 makeCertificateInternal(string subject,
bool switchToMtaIfNeeded, X509Certificate2 signingCert = null, bool switchToMtaIfNeeded, X509Certificate2? signingCert = null,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
return makeCertificateInternal(isRoot, subject, $"CN={subject}", return makeCertificateInternal(subject, $"CN={subject}",
DateTime.UtcNow.AddDays(-certificateGraceDays), DateTime.UtcNow.AddDays(certificateValidDays), DateTime.UtcNow.AddDays(-certificateGraceDays), DateTime.UtcNow.AddDays(certificateValidDays),
isRoot ? null : signingCert); signingCert);
} }
} }
} }
...@@ -7,6 +7,6 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -7,6 +7,6 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// </summary> /// </summary>
internal interface ICertificateMaker internal interface ICertificateMaker
{ {
X509Certificate2 MakeCertificate(string sSubjectCn, bool isRoot, X509Certificate2 signingCert); X509Certificate2 MakeCertificate(string sSubjectCn, X509Certificate2? signingCert);
} }
} }
...@@ -75,18 +75,18 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -75,18 +75,18 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <summary> /// <summary>
/// Make certificate. /// Make certificate.
/// </summary> /// </summary>
public X509Certificate2 MakeCertificate(string sSubjectCN, bool isRoot, X509Certificate2 signingCert = null) public X509Certificate2 MakeCertificate(string sSubjectCN, X509Certificate2? signingCert = null)
{ {
return makeCertificate(sSubjectCN, isRoot, true, signingCert); return makeCertificate(sSubjectCN, true, signingCert);
} }
private X509Certificate2 makeCertificate(string sSubjectCN, bool isRoot, private X509Certificate2 makeCertificate(string sSubjectCN,
bool switchToMTAIfNeeded, X509Certificate2 signingCert = null, bool switchToMTAIfNeeded, X509Certificate2? signingCertificate = null,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
if (switchToMTAIfNeeded && Thread.CurrentThread.GetApartmentState() != ApartmentState.MTA) if (switchToMTAIfNeeded && Thread.CurrentThread.GetApartmentState() != ApartmentState.MTA)
{ {
return Task.Run(() => makeCertificate(sSubjectCN, isRoot, false, signingCert), return Task.Run(() => makeCertificate(sSubjectCN, false, signingCertificate),
cancellationToken).Result; cancellationToken).Result;
} }
...@@ -107,37 +107,30 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -107,37 +107,30 @@ namespace Titanium.Web.Proxy.Network.Certificate
var now = DateTime.Now; var now = DateTime.Now;
var graceTime = now.AddDays(graceDays); var graceTime = now.AddDays(graceDays);
var certificate = makeCertificate(isRoot, sSubjectCN, fullSubject, keyLength, hashAlgo, graceTime, var certificate = makeCertificate(sSubjectCN, fullSubject, keyLength, hashAlgo, graceTime,
now.AddDays(validDays), isRoot ? null : signingCert); now.AddDays(validDays), signingCertificate);
return certificate; return certificate;
} }
private X509Certificate2 makeCertificate(bool isRoot, string subject, string fullSubject, private X509Certificate2 makeCertificate(string subject, string fullSubject,
int privateKeyLength, string hashAlg, DateTime validFrom, DateTime validTo, int privateKeyLength, string hashAlg, DateTime validFrom, DateTime validTo,
X509Certificate2 signingCertificate) X509Certificate2? signingCertificate)
{ {
if (isRoot != (null == signingCertificate))
{
throw new ArgumentException(
"You must specify a Signing Certificate if and only if you are not creating a root.",
nameof(isRoot));
}
var x500CertDN = Activator.CreateInstance(typeX500DN); var x500CertDN = Activator.CreateInstance(typeX500DN);
var typeValue = new object[] { fullSubject, 0 }; var typeValue = new object[] { fullSubject, 0 };
typeX500DN.InvokeMember("Encode", BindingFlags.InvokeMethod, null, x500CertDN, typeValue); typeX500DN.InvokeMember("Encode", BindingFlags.InvokeMethod, null, x500CertDN, typeValue);
var x500RootCertDN = Activator.CreateInstance(typeX500DN); var x500RootCertDN = Activator.CreateInstance(typeX500DN);
if (!isRoot) if (signingCertificate != null)
{ {
typeValue[0] = signingCertificate.Subject; typeValue[0] = signingCertificate.Subject;
} }
typeX500DN.InvokeMember("Encode", BindingFlags.InvokeMethod, null, x500RootCertDN, typeValue); typeX500DN.InvokeMember("Encode", BindingFlags.InvokeMethod, null, x500RootCertDN, typeValue);
object sharedPrivateKey = null; object? sharedPrivateKey = null;
if (!isRoot) if (signingCertificate != null)
{ {
sharedPrivateKey = this.sharedPrivateKey; sharedPrivateKey = this.sharedPrivateKey;
} }
...@@ -151,11 +144,11 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -151,11 +144,11 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeValue[0] = 2; typeValue[0] = 2;
typeX509PrivateKey.InvokeMember("ExportPolicy", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeX509PrivateKey.InvokeMember("ExportPolicy", BindingFlags.PutDispProperty, null, sharedPrivateKey,
typeValue); typeValue);
typeValue = new object[] { isRoot ? 2 : 1 }; typeValue = new object[] { signingCertificate == null ? 2 : 1 };
typeX509PrivateKey.InvokeMember("KeySpec", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeX509PrivateKey.InvokeMember("KeySpec", BindingFlags.PutDispProperty, null, sharedPrivateKey,
typeValue); typeValue);
if (!isRoot) if (signingCertificate != null)
{ {
typeValue = new object[] { 176 }; typeValue = new object[] { 176 };
typeX509PrivateKey.InvokeMember("KeyUsage", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeX509PrivateKey.InvokeMember("KeyUsage", BindingFlags.PutDispProperty, null, sharedPrivateKey,
...@@ -167,7 +160,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -167,7 +160,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeValue); typeValue);
typeX509PrivateKey.InvokeMember("Create", BindingFlags.InvokeMethod, null, sharedPrivateKey, null); typeX509PrivateKey.InvokeMember("Create", BindingFlags.InvokeMethod, null, sharedPrivateKey, null);
if (!isRoot) if (signingCertificate != null)
{ {
this.sharedPrivateKey = sharedPrivateKey; this.sharedPrivateKey = sharedPrivateKey;
} }
...@@ -210,7 +203,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -210,7 +203,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeRequestCert.InvokeMember("X509Extensions", BindingFlags.GetProperty, null, requestCert, null); typeRequestCert.InvokeMember("X509Extensions", BindingFlags.GetProperty, null, requestCert, null);
typeValue = new object[1]; typeValue = new object[1];
if (!isRoot) if (signingCertificate != null)
{ {
typeValue[0] = kuExt; typeValue[0] = kuExt;
typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue); typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue);
...@@ -219,7 +212,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -219,7 +212,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeValue[0] = ekuExt; typeValue[0] = ekuExt;
typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue); typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue);
if (!isRoot) if (signingCertificate != null)
{ {
// add alternative names // add alternative names
// https://forums.iis.net/t/1180823.aspx // https://forums.iis.net/t/1180823.aspx
...@@ -244,7 +237,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -244,7 +237,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue); typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue);
} }
if (!isRoot) if (signingCertificate != null)
{ {
var signerCertificate = Activator.CreateInstance(typeSignerCertificate); var signerCertificate = Activator.CreateInstance(typeSignerCertificate);
...@@ -281,7 +274,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -281,7 +274,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeX509Enrollment.InvokeMember("InitializeFromRequest", BindingFlags.InvokeMethod, null, x509Enrollment, typeX509Enrollment.InvokeMember("InitializeFromRequest", BindingFlags.InvokeMethod, null, x509Enrollment,
typeValue); typeValue);
if (isRoot) if (signingCertificate == null)
{ {
typeValue[0] = fullSubject; typeValue[0] = fullSubject;
typeX509Enrollment.InvokeMember("CertificateFriendlyName", BindingFlags.PutDispProperty, null, typeX509Enrollment.InvokeMember("CertificateFriendlyName", BindingFlags.PutDispProperty, null,
...@@ -296,7 +289,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -296,7 +289,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeX509Enrollment.InvokeMember("InstallResponse", BindingFlags.InvokeMethod, null, x509Enrollment, typeX509Enrollment.InvokeMember("InstallResponse", BindingFlags.InvokeMethod, null, x509Enrollment,
typeValue); typeValue);
typeValue = new object[] { null, 0, 1 }; typeValue = new object[] { null!, 0, 1 };
string empty = (string)typeX509Enrollment.InvokeMember("CreatePFX", BindingFlags.InvokeMethod, null, string empty = (string)typeX509Enrollment.InvokeMember("CreatePFX", BindingFlags.InvokeMethod, null,
x509Enrollment, typeValue); x509Enrollment, typeValue);
......
...@@ -66,7 +66,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -66,7 +66,7 @@ namespace Titanium.Web.Proxy.Network
private string issuer; private string issuer;
private X509Certificate2 rootCertificate; private X509Certificate2? rootCertificate;
private string rootCertificateName; private string rootCertificateName;
...@@ -87,7 +87,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -87,7 +87,7 @@ namespace Titanium.Web.Proxy.Network
/// prompting for UAC if required? /// prompting for UAC if required?
/// </param> /// </param>
/// <param name="exceptionFunc"></param> /// <param name="exceptionFunc"></param>
internal CertificateManager(string rootCertificateName, string rootCertificateIssuerName, internal CertificateManager(string? rootCertificateName, string? rootCertificateIssuerName,
bool userTrustRootCertificate, bool machineTrustRootCertificate, bool trustRootCertificateAsAdmin, bool userTrustRootCertificate, bool machineTrustRootCertificate, bool trustRootCertificateAsAdmin,
ExceptionHandler exceptionFunc) ExceptionHandler exceptionFunc)
{ {
...@@ -156,7 +156,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -156,7 +156,7 @@ namespace Titanium.Web.Proxy.Network
if (value != engine) if (value != engine)
{ {
certEngine = null; certEngine = null!;
engine = value; engine = value;
} }
...@@ -210,7 +210,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -210,7 +210,7 @@ namespace Titanium.Web.Proxy.Network
/// <summary> /// <summary>
/// The root certificate. /// The root certificate.
/// </summary> /// </summary>
public X509Certificate2 RootCertificate public X509Certificate2? RootCertificate
{ {
get => rootCertificate; get => rootCertificate;
set set
...@@ -268,6 +268,11 @@ namespace Titanium.Web.Proxy.Network ...@@ -268,6 +268,11 @@ namespace Titanium.Web.Proxy.Network
/// <returns></returns> /// <returns></returns>
private bool rootCertificateInstalled(StoreLocation storeLocation) private bool rootCertificateInstalled(StoreLocation storeLocation)
{ {
if (RootCertificate == null)
{
throw new Exception("Root certificate is null.");
}
string value = $"{RootCertificate.Issuer}"; string value = $"{RootCertificate.Issuer}";
return findCertificates(StoreName.Root, storeLocation, value).Count > 0 return findCertificates(StoreName.Root, storeLocation, value).Count > 0
&& (CertificateEngine != CertificateEngine.DefaultWindows && (CertificateEngine != CertificateEngine.DefaultWindows
...@@ -298,8 +303,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -298,8 +303,7 @@ namespace Titanium.Web.Proxy.Network
{ {
if (RootCertificate == null) if (RootCertificate == null)
{ {
ExceptionFunc(new Exception("Could not install certificate as it is null or empty.")); throw new Exception("Could not install certificate as it is null or empty.");
return;
} }
var x509Store = new X509Store(storeName, storeLocation); var x509Store = new X509Store(storeName, storeLocation);
...@@ -361,12 +365,19 @@ namespace Titanium.Web.Proxy.Network ...@@ -361,12 +365,19 @@ namespace Titanium.Web.Proxy.Network
private X509Certificate2 makeCertificate(string certificateName, bool isRootCertificate) private X509Certificate2 makeCertificate(string certificateName, bool isRootCertificate)
{ {
//if (isRoot != (null == signingCertificate))
//{
// throw new ArgumentException(
// "You must specify a Signing Certificate if and only if you are not creating a root.",
// nameof(signingCertificate));
//}
if (!isRootCertificate && RootCertificate == null) if (!isRootCertificate && RootCertificate == null)
{ {
CreateRootCertificate(); CreateRootCertificate();
} }
var certificate = certEngine.MakeCertificate(certificateName, isRootCertificate, RootCertificate); var certificate = certEngine.MakeCertificate(certificateName, isRootCertificate ? null : RootCertificate);
if (CertificateEngine == CertificateEngine.DefaultWindows) if (CertificateEngine == CertificateEngine.DefaultWindows)
{ {
...@@ -382,9 +393,9 @@ namespace Titanium.Web.Proxy.Network ...@@ -382,9 +393,9 @@ namespace Titanium.Web.Proxy.Network
/// <param name="certificateName"></param> /// <param name="certificateName"></param>
/// <param name="isRootCertificate"></param> /// <param name="isRootCertificate"></param>
/// <returns></returns> /// <returns></returns>
internal X509Certificate2 CreateCertificate(string certificateName, bool isRootCertificate) internal X509Certificate2? CreateCertificate(string certificateName, bool isRootCertificate)
{ {
X509Certificate2 certificate; X509Certificate2? certificate;
try try
{ {
if (!isRootCertificate && SaveFakeCertificates) if (!isRootCertificate && SaveFakeCertificates)
...@@ -589,7 +600,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -589,7 +600,7 @@ namespace Titanium.Web.Proxy.Network
/// Loads root certificate from current executing assembly location with expected name rootCert.pfx. /// Loads root certificate from current executing assembly location with expected name rootCert.pfx.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public X509Certificate2 LoadRootCertificate() public X509Certificate2? LoadRootCertificate()
{ {
try try
{ {
...@@ -671,7 +682,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -671,7 +682,7 @@ namespace Titanium.Web.Proxy.Network
installCertificate(StoreName.My, StoreLocation.CurrentUser); installCertificate(StoreName.My, StoreLocation.CurrentUser);
string pfxFileName = Path.GetTempFileName(); string pfxFileName = Path.GetTempFileName();
File.WriteAllBytes(pfxFileName, RootCertificate.Export(X509ContentType.Pkcs12, PfxPassword)); File.WriteAllBytes(pfxFileName, RootCertificate!.Export(X509ContentType.Pkcs12, PfxPassword));
// currentUser\Root, currentMachine\Personal & currentMachine\Root // currentUser\Root, currentMachine\Personal & currentMachine\Root
var info = new ProcessStartInfo var info = new ProcessStartInfo
......
...@@ -11,10 +11,10 @@ namespace Titanium.Web.Proxy.Network ...@@ -11,10 +11,10 @@ namespace Titanium.Web.Proxy.Network
private const string defaultCertificateDirectoryName = "crts"; private const string defaultCertificateDirectoryName = "crts";
private const string defaultCertificateFileExtension = ".pfx"; private const string defaultCertificateFileExtension = ".pfx";
private const string defaultRootCertificateFileName = "rootCert" + defaultCertificateFileExtension; private const string defaultRootCertificateFileName = "rootCert" + defaultCertificateFileExtension;
private string rootCertificatePath; private string? rootCertificatePath;
private string certificatePath; private string? certificatePath;
public X509Certificate2 LoadRootCertificate(string pathOrName, string password, X509KeyStorageFlags storageFlags) public X509Certificate2? LoadRootCertificate(string pathOrName, string password, X509KeyStorageFlags storageFlags)
{ {
string path = getRootCertificatePath(pathOrName); string path = getRootCertificatePath(pathOrName);
return loadCertificate(path, password, storageFlags); return loadCertificate(path, password, storageFlags);
...@@ -28,7 +28,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -28,7 +28,7 @@ namespace Titanium.Web.Proxy.Network
} }
/// <inheritdoc /> /// <inheritdoc />
public X509Certificate2 LoadCertificate(string subjectName, X509KeyStorageFlags storageFlags) public X509Certificate2? LoadCertificate(string subjectName, X509KeyStorageFlags storageFlags)
{ {
string path = Path.Combine(getCertificatePath(), subjectName + defaultCertificateFileExtension); string path = Path.Combine(getCertificatePath(), subjectName + defaultCertificateFileExtension);
return loadCertificate(path, string.Empty, storageFlags); return loadCertificate(path, string.Empty, storageFlags);
...@@ -56,7 +56,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -56,7 +56,7 @@ namespace Titanium.Web.Proxy.Network
certificatePath = null; certificatePath = null;
} }
private X509Certificate2 loadCertificate(string path, string password, X509KeyStorageFlags storageFlags) private X509Certificate2? loadCertificate(string path, string password, X509KeyStorageFlags storageFlags)
{ {
byte[] exported; byte[] exported;
......
...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Network
private readonly int retries; private readonly int retries;
private readonly TcpConnectionFactory tcpConnectionFactory; private readonly TcpConnectionFactory tcpConnectionFactory;
private TcpServerConnection currentConnection; private TcpServerConnection? currentConnection;
internal RetryPolicy(int retries, TcpConnectionFactory tcpConnectionFactory) internal RetryPolicy(int retries, TcpConnectionFactory tcpConnectionFactory)
{ {
...@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy.Network
{ {
currentConnection = initialConnection; currentConnection = initialConnection;
bool @continue = true; bool @continue = true;
Exception exception = null; Exception? exception = null;
var attempts = retries; var attempts = retries;
...@@ -80,11 +80,14 @@ namespace Titanium.Web.Proxy.Network ...@@ -80,11 +80,14 @@ namespace Titanium.Web.Proxy.Network
internal class RetryResult internal class RetryResult
{ {
internal bool IsSuccess => Exception == null; internal bool IsSuccess => Exception == null;
internal TcpServerConnection LatestConnection { get; } internal TcpServerConnection LatestConnection { get; }
internal Exception Exception { get; }
internal Exception? Exception { get; }
internal bool Continue { get; } internal bool Continue { get; }
internal RetryResult(TcpServerConnection lastConnection, Exception exception, bool @continue) internal RetryResult(TcpServerConnection lastConnection, Exception? exception, bool @continue)
{ {
LatestConnection = lastConnection; LatestConnection = lastConnection;
Exception = exception; Exception = exception;
......
...@@ -47,7 +47,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -47,7 +47,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
internal ProxyServer Server { get; } internal ProxyServer Server { get; }
internal string GetConnectionCacheKey(string remoteHostName, int remotePort, internal string GetConnectionCacheKey(string remoteHostName, int remotePort,
bool isHttps, List<SslApplicationProtocol> applicationProtocols, bool isHttps, List<SslApplicationProtocol>? applicationProtocols,
IPEndPoint upStreamEndPoint, ExternalProxy externalProxy) IPEndPoint upStreamEndPoint, ExternalProxy externalProxy)
{ {
// http version is ignored since its an application level decision b/w HTTP 1.0/1.1 // http version is ignored since its an application level decision b/w HTTP 1.0/1.1
...@@ -83,13 +83,13 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -83,13 +83,13 @@ namespace Titanium.Web.Proxy.Network.Tcp
internal async Task<string> GetConnectionCacheKey(ProxyServer server, SessionEventArgsBase session, internal async Task<string> GetConnectionCacheKey(ProxyServer server, SessionEventArgsBase session,
SslApplicationProtocol applicationProtocol) SslApplicationProtocol applicationProtocol)
{ {
List<SslApplicationProtocol> applicationProtocols = null; List<SslApplicationProtocol>? applicationProtocols = null;
if (applicationProtocol != default) if (applicationProtocol != default)
{ {
applicationProtocols = new List<SslApplicationProtocol> { applicationProtocol }; applicationProtocols = new List<SslApplicationProtocol> { applicationProtocol };
} }
ExternalProxy customUpStreamProxy = null; ExternalProxy? customUpStreamProxy = null;
bool isHttps = session.IsHttps; bool isHttps = session.IsHttps;
if (server.GetCustomUpStreamProxyFunc != null) if (server.GetCustomUpStreamProxyFunc != null)
...@@ -121,7 +121,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -121,7 +121,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
internal Task<TcpServerConnection> GetServerConnection(ProxyServer server, SessionEventArgsBase session, bool isConnect, internal Task<TcpServerConnection> GetServerConnection(ProxyServer server, SessionEventArgsBase session, bool isConnect,
SslApplicationProtocol applicationProtocol, bool noCache, CancellationToken cancellationToken) SslApplicationProtocol applicationProtocol, bool noCache, CancellationToken cancellationToken)
{ {
List<SslApplicationProtocol> applicationProtocols = null; List<SslApplicationProtocol>? applicationProtocols = null;
if (applicationProtocol != default) if (applicationProtocol != default)
{ {
applicationProtocols = new List<SslApplicationProtocol> { applicationProtocol }; applicationProtocols = new List<SslApplicationProtocol> { applicationProtocol };
...@@ -141,9 +141,9 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -141,9 +141,9 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <param name="cancellationToken">The cancellation token for this async task.</param> /// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns> /// <returns></returns>
internal async Task<TcpServerConnection> GetServerConnection(ProxyServer server, SessionEventArgsBase session, bool isConnect, internal async Task<TcpServerConnection> GetServerConnection(ProxyServer server, SessionEventArgsBase session, bool isConnect,
List<SslApplicationProtocol> applicationProtocols, bool noCache, CancellationToken cancellationToken) List<SslApplicationProtocol>? applicationProtocols, bool noCache, CancellationToken cancellationToken)
{ {
ExternalProxy customUpStreamProxy = null; ExternalProxy? customUpStreamProxy = null;
bool isHttps = session.IsHttps; bool isHttps = session.IsHttps;
if (server.GetCustomUpStreamProxyFunc != null) if (server.GetCustomUpStreamProxyFunc != null)
...@@ -179,11 +179,11 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -179,11 +179,11 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <param name="cancellationToken">The cancellation token for this async task.</param> /// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns> /// <returns></returns>
internal async Task<TcpServerConnection> GetServerConnection(string remoteHostName, int remotePort, internal async Task<TcpServerConnection> GetServerConnection(string remoteHostName, int remotePort,
Version httpVersion, bool isHttps, List<SslApplicationProtocol> applicationProtocols, bool isConnect, Version httpVersion, bool isHttps, List<SslApplicationProtocol>? applicationProtocols, bool isConnect,
ProxyServer proxyServer, SessionEventArgsBase session, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy, ProxyServer proxyServer, SessionEventArgsBase? session, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy,
bool noCache, CancellationToken cancellationToken) bool noCache, CancellationToken cancellationToken)
{ {
var sslProtocol = session.ProxyClient.Connection.SslProtocol; var sslProtocol = session?.ProxyClient.Connection.SslProtocol ?? SslProtocols.None;
var cacheKey = GetConnectionCacheKey(remoteHostName, remotePort, var cacheKey = GetConnectionCacheKey(remoteHostName, remotePort,
isHttps, applicationProtocols, upStreamEndPoint, externalProxy); isHttps, applicationProtocols, upStreamEndPoint, externalProxy);
...@@ -269,8 +269,8 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -269,8 +269,8 @@ namespace Titanium.Web.Proxy.Network.Tcp
} }
} }
TcpClient tcpClient = null; TcpClient? tcpClient = null;
CustomBufferedStream stream = null; CustomBufferedStream? stream = null;
SslApplicationProtocol negotiatedApplicationProtocol = default; SslApplicationProtocol negotiatedApplicationProtocol = default;
...@@ -280,8 +280,8 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -280,8 +280,8 @@ namespace Titanium.Web.Proxy.Network.Tcp
retry: retry:
try try
{ {
var hostname = useUpstreamProxy ? externalProxy.HostName : remoteHostName; var hostname = useUpstreamProxy ? externalProxy!.HostName : remoteHostName;
var port = useUpstreamProxy ? externalProxy.Port : remotePort; var port = useUpstreamProxy ? externalProxy!.Port : remotePort;
var ipAddresses = await Dns.GetHostAddressesAsync(hostname); var ipAddresses = await Dns.GetHostAddressesAsync(hostname);
if (ipAddresses == null || ipAddresses.Length == 0) if (ipAddresses == null || ipAddresses.Length == 0)
...@@ -341,9 +341,9 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -341,9 +341,9 @@ namespace Titanium.Web.Proxy.Network.Tcp
session.TimeLine["Connection Established"] = DateTime.Now; session.TimeLine["Connection Established"] = DateTime.Now;
} }
await proxyServer.InvokeConnectionCreateEvent(tcpClient, false); await proxyServer.InvokeConnectionCreateEvent(tcpClient!, false);
stream = new CustomBufferedStream(tcpClient.GetStream(), proxyServer.BufferPool); stream = new CustomBufferedStream(tcpClient!.GetStream(), proxyServer.BufferPool);
if (useUpstreamProxy && (isConnect || isHttps)) if (useUpstreamProxy && (isConnect || isHttps))
{ {
...@@ -356,7 +356,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -356,7 +356,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
connectRequest.Headers.AddHeader(KnownHeaders.Connection, KnownHeaders.ConnectionKeepAlive); connectRequest.Headers.AddHeader(KnownHeaders.Connection, KnownHeaders.ConnectionKeepAlive);
if (!string.IsNullOrEmpty(externalProxy.UserName) && externalProxy.Password != null) if (!string.IsNullOrEmpty(externalProxy!.UserName) && externalProxy.Password != null)
{ {
connectRequest.Headers.AddHeader(HttpHeader.ProxyConnectionKeepAlive); connectRequest.Headers.AddHeader(HttpHeader.ProxyConnectionKeepAlive);
connectRequest.Headers.AddHeader( connectRequest.Headers.AddHeader(
...@@ -388,7 +388,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -388,7 +388,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
{ {
ApplicationProtocols = applicationProtocols, ApplicationProtocols = applicationProtocols,
TargetHost = remoteHostName, TargetHost = remoteHostName,
ClientCertificates = null, ClientCertificates = null!,
EnabledSslProtocols = enabledSslProtocols, EnabledSslProtocols = enabledSslProtocols,
CertificateRevocationCheckMode = proxyServer.CheckCertificateRevocation CertificateRevocationCheckMode = proxyServer.CheckCertificateRevocation
}; };
...@@ -440,11 +440,6 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -440,11 +440,6 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <param name="close">Should we just close the connection instead of reusing?</param> /// <param name="close">Should we just close the connection instead of reusing?</param>
internal async Task Release(TcpServerConnection connection, bool close = false) internal async Task Release(TcpServerConnection connection, bool close = false)
{ {
if (connection == null)
{
return;
}
if (close || connection.IsWinAuthenticated || !Server.EnableConnectionPool || connection.IsClosed) if (close || connection.IsWinAuthenticated || !Server.EnableConnectionPool || connection.IsClosed)
{ {
disposalBag.Add(connection); disposalBag.Add(connection);
...@@ -491,18 +486,21 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -491,18 +486,21 @@ namespace Titanium.Web.Proxy.Network.Tcp
{ {
if (connectionCreateTask != null) if (connectionCreateTask != null)
{ {
TcpServerConnection connection = null; TcpServerConnection? connection = null;
try try
{ {
connection = await connectionCreateTask; connection = await connectionCreateTask;
} }
catch { } catch { }
finally finally
{
if (connection != null)
{ {
await Release(connection, closeServerConnection); await Release(connection, closeServerConnection);
} }
} }
} }
}
private async Task clearOutdatedConnections() private async Task clearOutdatedConnections()
{ {
......
...@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
internal bool IsClosed => Stream.IsClosed; internal bool IsClosed => Stream.IsClosed;
internal ExternalProxy UpStreamProxy { get; set; } internal ExternalProxy? UpStreamProxy { get; set; }
internal string HostName { get; set; } internal string HostName { get; set; }
...@@ -44,7 +44,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -44,7 +44,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary> /// <summary>
/// Local NIC via connection is made /// Local NIC via connection is made
/// </summary> /// </summary>
internal IPEndPoint UpStreamEndPoint { get; set; } internal IPEndPoint? UpStreamEndPoint { get; set; }
/// <summary> /// <summary>
/// Http version /// Http version
...@@ -61,7 +61,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -61,7 +61,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary> /// <summary>
/// Used to write lines to server /// Used to write lines to server
/// </summary> /// </summary>
internal HttpRequestWriter StreamWriter { get; set; } internal HttpRequestWriter? StreamWriter { get; set; }
/// <summary> /// <summary>
/// Server stream /// Server stream
......
...@@ -224,9 +224,9 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -224,9 +224,9 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
} }
} }
internal byte[] GetBytes() internal byte[]? GetBytes()
{ {
byte[] buffer = null; byte[]? buffer = null;
if (pBuffers == IntPtr.Zero) if (pBuffers == IntPtr.Zero)
{ {
......
...@@ -24,9 +24,9 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -24,9 +24,9 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
/// <param name="authScheme"></param> /// <param name="authScheme"></param>
/// <param name="data"></param> /// <param name="data"></param>
/// <returns></returns> /// <returns></returns>
internal static byte[] AcquireInitialSecurityToken(string hostname, string authScheme, InternalDataStore data) internal static byte[]? AcquireInitialSecurityToken(string hostname, string authScheme, InternalDataStore data)
{ {
byte[] token; byte[]? token;
// null for initial call // null for initial call
var serverToken = new SecurityBufferDesciption(); var serverToken = new SecurityBufferDesciption();
...@@ -91,9 +91,9 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -91,9 +91,9 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
/// <param name="serverChallenge"></param> /// <param name="serverChallenge"></param>
/// <param name="data"></param> /// <param name="data"></param>
/// <returns></returns> /// <returns></returns>
internal static byte[] AcquireFinalSecurityToken(string hostname, byte[] serverChallenge, InternalDataStore data) internal static byte[]? AcquireFinalSecurityToken(string hostname, byte[] serverChallenge, InternalDataStore data)
{ {
byte[] token; byte[]? token;
// user server challenge // user server challenge
var serverToken = new SecurityBufferDesciption(serverChallenge); var serverToken = new SecurityBufferDesciption(serverChallenge);
...@@ -145,19 +145,19 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -145,19 +145,19 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
/// <returns></returns> /// <returns></returns>
internal static bool ValidateWinAuthState(InternalDataStore data, State.WinAuthState expectedAuthState) internal static bool ValidateWinAuthState(InternalDataStore data, State.WinAuthState expectedAuthState)
{ {
bool stateExists = data.TryGetValueAs(authStateKey, out State state); bool stateExists = data.TryGetValueAs(authStateKey, out State? state);
if (expectedAuthState == State.WinAuthState.UNAUTHORIZED) if (expectedAuthState == State.WinAuthState.UNAUTHORIZED)
{ {
return !stateExists || return !stateExists ||
state.AuthState == State.WinAuthState.UNAUTHORIZED || state!.AuthState == State.WinAuthState.UNAUTHORIZED ||
state.AuthState == State.WinAuthState.AUTHORIZED; // Server may require re-authentication on an open connection state.AuthState == State.WinAuthState.AUTHORIZED; // Server may require re-authentication on an open connection
} }
if (expectedAuthState == State.WinAuthState.INITIAL_TOKEN) if (expectedAuthState == State.WinAuthState.INITIAL_TOKEN)
{ {
return stateExists && return stateExists &&
(state.AuthState == State.WinAuthState.INITIAL_TOKEN || (state!.AuthState == State.WinAuthState.INITIAL_TOKEN ||
state.AuthState == State.WinAuthState.AUTHORIZED); // Server may require re-authentication on an open connection state.AuthState == State.WinAuthState.AUTHORIZED); // Server may require re-authentication on an open connection
} }
...@@ -170,9 +170,9 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -170,9 +170,9 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
/// <param name="data"></param> /// <param name="data"></param>
internal static void AuthenticatedResponse(InternalDataStore data) internal static void AuthenticatedResponse(InternalDataStore data)
{ {
if (data.TryGetValueAs(authStateKey, out State state)) if (data.TryGetValueAs(authStateKey, out State? state))
{ {
state.AuthState = State.WinAuthState.AUTHORIZED; state!.AuthState = State.WinAuthState.AUTHORIZED;
state.UpdatePresence(); state.UpdatePresence();
} }
} }
......
...@@ -118,7 +118,7 @@ namespace Titanium.Web.Proxy ...@@ -118,7 +118,7 @@ namespace Titanium.Web.Proxy
/// <param name="description">Response description.</param> /// <param name="description">Response description.</param>
/// <param name="continuation">The continuation.</param> /// <param name="continuation">The continuation.</param>
/// <returns></returns> /// <returns></returns>
private Response createAuthentication407Response(string description, string continuation = null) private Response createAuthentication407Response(string description, string? continuation = null)
{ {
var response = new Response var response = new Response
{ {
......
...@@ -91,7 +91,7 @@ namespace Titanium.Web.Proxy ...@@ -91,7 +91,7 @@ namespace Titanium.Web.Proxy
/// Should we attempt to trust certificates with elevated permissions by /// Should we attempt to trust certificates with elevated permissions by
/// prompting for UAC if required? /// prompting for UAC if required?
/// </param> /// </param>
public ProxyServer(string rootCertificateName, string rootCertificateIssuerName, public ProxyServer(string? rootCertificateName, string? rootCertificateIssuerName,
bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false,
bool trustRootCertificateAsAdmin = false) bool trustRootCertificateAsAdmin = false)
{ {
...@@ -229,7 +229,9 @@ namespace Titanium.Web.Proxy ...@@ -229,7 +229,9 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// List of supported Ssl versions. /// List of supported Ssl versions.
/// </summary> /// </summary>
#pragma warning disable 618
public SslProtocols SupportedSslProtocols { get; set; } = SslProtocols.Ssl3 | SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12; public SslProtocols SupportedSslProtocols { get; set; } = SslProtocols.Ssl3 | SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
#pragma warning restore 618
/// <summary> /// <summary>
/// The buffer pool used throughout this proxy instance. /// The buffer pool used throughout this proxy instance.
...@@ -307,37 +309,37 @@ namespace Titanium.Web.Proxy ...@@ -307,37 +309,37 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Event occurs when client connection count changed. /// Event occurs when client connection count changed.
/// </summary> /// </summary>
public event EventHandler ClientConnectionCountChanged; public event EventHandler? ClientConnectionCountChanged;
/// <summary> /// <summary>
/// Event occurs when server connection count changed. /// Event occurs when server connection count changed.
/// </summary> /// </summary>
public event EventHandler ServerConnectionCountChanged; public event EventHandler? ServerConnectionCountChanged;
/// <summary> /// <summary>
/// Event to override the default verification logic of remote SSL certificate received during authentication. /// Event to override the default verification logic of remote SSL certificate received during authentication.
/// </summary> /// </summary>
public event AsyncEventHandler<CertificateValidationEventArgs> ServerCertificateValidationCallback; public event AsyncEventHandler<CertificateValidationEventArgs>? ServerCertificateValidationCallback;
/// <summary> /// <summary>
/// Event to override client certificate selection during mutual SSL authentication. /// Event to override client certificate selection during mutual SSL authentication.
/// </summary> /// </summary>
public event AsyncEventHandler<CertificateSelectionEventArgs> ClientCertificateSelectionCallback; public event AsyncEventHandler<CertificateSelectionEventArgs>? ClientCertificateSelectionCallback;
/// <summary> /// <summary>
/// Intercept request event to server. /// Intercept request event to server.
/// </summary> /// </summary>
public event AsyncEventHandler<SessionEventArgs> BeforeRequest; public event AsyncEventHandler<SessionEventArgs>? BeforeRequest;
/// <summary> /// <summary>
/// Intercept response event from server. /// Intercept response event from server.
/// </summary> /// </summary>
public event AsyncEventHandler<SessionEventArgs> BeforeResponse; public event AsyncEventHandler<SessionEventArgs>? BeforeResponse;
/// <summary> /// <summary>
/// Intercept after response event from server. /// Intercept after response event from server.
/// </summary> /// </summary>
public event AsyncEventHandler<SessionEventArgs> AfterResponse; public event AsyncEventHandler<SessionEventArgs>? AfterResponse;
/// <summary> /// <summary>
/// Customize TcpClient used for client connection upon create. /// Customize TcpClient used for client connection upon create.
...@@ -471,7 +473,7 @@ namespace Titanium.Web.Proxy ...@@ -471,7 +473,7 @@ namespace Titanium.Web.Proxy
endPoint.IsSystemHttpsProxy = true; endPoint.IsSystemHttpsProxy = true;
} }
string proxyType = null; string? proxyType = null;
switch (protocolType) switch (protocolType)
{ {
case ProxyProtocolType.Http: case ProxyProtocolType.Http:
...@@ -572,7 +574,7 @@ namespace Titanium.Web.Proxy ...@@ -572,7 +574,7 @@ namespace Titanium.Web.Proxy
if (systemProxySettingsManager != null && RunTime.IsWindows && !RunTime.IsUwpOnWindows) if (systemProxySettingsManager != null && RunTime.IsWindows && !RunTime.IsUwpOnWindows)
{ {
var proxyInfo = systemProxySettingsManager.GetProxyInfoFromRegistry(); var proxyInfo = systemProxySettingsManager.GetProxyInfoFromRegistry();
if (proxyInfo.Proxies != null) if (proxyInfo?.Proxies != null)
{ {
var protocolToRemove = ProxyProtocolType.None; var protocolToRemove = ProxyProtocolType.None;
foreach (var proxy in proxyInfo.Proxies.Values) foreach (var proxy in proxyInfo.Proxies.Values)
...@@ -717,7 +719,7 @@ namespace Titanium.Web.Proxy ...@@ -717,7 +719,7 @@ namespace Titanium.Web.Proxy
{ {
var endPoint = (ProxyEndPoint)asyn.AsyncState; var endPoint = (ProxyEndPoint)asyn.AsyncState;
TcpClient tcpClient = null; TcpClient? tcpClient = null;
try try
{ {
......
...@@ -45,7 +45,7 @@ namespace Titanium.Web.Proxy ...@@ -45,7 +45,7 @@ namespace Titanium.Web.Proxy
/// <param name="prefetchConnectionTask">Prefetched server connection for current client using Connect/SNI headers.</param> /// <param name="prefetchConnectionTask">Prefetched server connection for current client using Connect/SNI headers.</param>
private async Task handleHttpSessionRequest(ProxyEndPoint endPoint, TcpClientConnection clientConnection, private async Task handleHttpSessionRequest(ProxyEndPoint endPoint, TcpClientConnection clientConnection,
CustomBufferedStream clientStream, HttpResponseWriter clientStreamWriter, CustomBufferedStream clientStream, HttpResponseWriter clientStreamWriter,
CancellationTokenSource cancellationTokenSource, string httpsConnectHostname, TunnelConnectSessionEventArgs connectArgs, CancellationTokenSource cancellationTokenSource, string? httpsConnectHostname, TunnelConnectSessionEventArgs? connectArgs,
Task<TcpServerConnection>? prefetchConnectionTask = null) Task<TcpServerConnection>? prefetchConnectionTask = null)
{ {
var connectRequest = connectArgs?.HttpClient.ConnectRequest; var connectRequest = connectArgs?.HttpClient.ConnectRequest;
...@@ -107,8 +107,8 @@ namespace Titanium.Web.Proxy ...@@ -107,8 +107,8 @@ namespace Titanium.Web.Proxy
} }
else else
{ {
string host = args.HttpClient.Request.Host ?? httpsConnectHostname; string? host = args.HttpClient.Request.Host ?? httpsConnectHostname;
string hostAndPath = host; string? hostAndPath = host;
if (httpUrl.StartsWith("/")) if (httpUrl.StartsWith("/"))
{ {
hostAndPath += httpUrl; hostAndPath += httpUrl;
...@@ -288,15 +288,17 @@ namespace Titanium.Web.Proxy ...@@ -288,15 +288,17 @@ namespace Titanium.Web.Proxy
} }
finally finally
{ {
await tcpConnectionFactory.Release(connection, if (connection != null)
closeServerConnection); {
await tcpConnectionFactory.Release(connection, closeServerConnection);
}
await tcpConnectionFactory.Release(prefetchTask, closeServerConnection); await tcpConnectionFactory.Release(prefetchTask, closeServerConnection);
} }
} }
private async Task<RetryResult> handleHttpSessionRequest(string requestHttpMethod, string requestHttpUrl, Version requestVersion, SessionEventArgs args, private async Task<RetryResult> handleHttpSessionRequest(string requestHttpMethod, string requestHttpUrl, Version requestVersion, SessionEventArgs args,
TcpServerConnection serverConnection, SslApplicationProtocol sslApplicationProtocol, TcpServerConnection? serverConnection, SslApplicationProtocol sslApplicationProtocol,
CancellationToken cancellationToken, CancellationTokenSource cancellationTokenSource) CancellationToken cancellationToken, CancellationTokenSource cancellationTokenSource)
{ {
// a connection generator task with captured parameters via closure. // a connection generator task with captured parameters via closure.
...@@ -312,7 +314,7 @@ namespace Titanium.Web.Proxy ...@@ -312,7 +314,7 @@ namespace Titanium.Web.Proxy
if (args.HttpClient.Request.UpgradeToWebSocket) if (args.HttpClient.Request.UpgradeToWebSocket)
{ {
args.HttpClient.ConnectRequest.TunnelType = TunnelType.Websocket; args.HttpClient.ConnectRequest!.TunnelType = TunnelType.Websocket;
// if upgrading to websocket then relay the request without reading the contents // if upgrading to websocket then relay the request without reading the contents
await handleWebSocketUpgrade(requestHttpMethod, requestHttpUrl, requestVersion, args, args.HttpClient.Request, await handleWebSocketUpgrade(requestHttpMethod, requestHttpUrl, requestVersion, args, args.HttpClient.Request,
...@@ -383,7 +385,7 @@ namespace Titanium.Web.Proxy ...@@ -383,7 +385,7 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
private void prepareRequestHeaders(HeaderCollection requestHeaders) private void prepareRequestHeaders(HeaderCollection requestHeaders)
{ {
string acceptEncoding = requestHeaders.GetHeaderValueOrNull(KnownHeaders.AcceptEncoding); string? acceptEncoding = requestHeaders.GetHeaderValueOrNull(KnownHeaders.AcceptEncoding);
if (acceptEncoding != null) if (acceptEncoding != null)
{ {
......
...@@ -72,8 +72,7 @@ namespace Titanium.Web.Proxy ...@@ -72,8 +72,7 @@ namespace Titanium.Web.Proxy
// write custom user response with body and return. // write custom user response with body and return.
await clientStreamWriter.WriteResponseAsync(response, cancellationToken: cancellationToken); await clientStreamWriter.WriteResponseAsync(response, cancellationToken: cancellationToken);
if (args.HttpClient.Connection != null if (args.HttpClient.HasConnection && !args.HttpClient.CloseServerConnection)
&& !args.HttpClient.CloseServerConnection)
{ {
// syphon out the original response body from server connection // syphon out the original response body from server connection
// so that connection will be good to be reused. // so that connection will be good to be reused.
...@@ -86,8 +85,11 @@ namespace Titanium.Web.Proxy ...@@ -86,8 +85,11 @@ namespace Titanium.Web.Proxy
// if user requested to send request again // if user requested to send request again
// likely after making modifications from User Response Handler // likely after making modifications from User Response Handler
if (args.ReRequest) if (args.ReRequest)
{
if (args.HttpClient.HasConnection)
{ {
await tcpConnectionFactory.Release(args.HttpClient.Connection); await tcpConnectionFactory.Release(args.HttpClient.Connection);
}
// clear current response // clear current response
await args.ClearResponse(cancellationToken); await args.ClearResponse(cancellationToken);
......
...@@ -40,7 +40,7 @@ namespace Titanium.Web.Proxy.StreamExtended ...@@ -40,7 +40,7 @@ namespace Titanium.Web.Proxy.StreamExtended
} }
} }
public byte[] SessionId { get; set; } public byte[] SessionId { get; }
public int[] Ciphers { get; set; } public int[] Ciphers { get; set; }
...@@ -50,7 +50,7 @@ namespace Titanium.Web.Proxy.StreamExtended ...@@ -50,7 +50,7 @@ namespace Titanium.Web.Proxy.StreamExtended
internal int EntensionsStartPosition { get; set; } internal int EntensionsStartPosition { get; set; }
public Dictionary<string, SslExtension> Extensions { get; set; } public Dictionary<string, SslExtension>? Extensions { get; set; }
public SslProtocols SslProtocol public SslProtocols SslProtocol
{ {
...@@ -79,6 +79,11 @@ namespace Titanium.Web.Proxy.StreamExtended ...@@ -79,6 +79,11 @@ namespace Titanium.Web.Proxy.StreamExtended
} }
} }
public ClientHelloInfo(byte[] sessionId)
{
SessionId = sessionId;
}
private static string SslVersionToString(int major, int minor) private static string SslVersionToString(int major, int minor)
{ {
string str = "Unknown"; string str = "Unknown";
......
...@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network ...@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
private int bufferLength; private int bufferLength;
private byte[] buffer; private readonly byte[] buffer;
private bool disposed; private bool disposed;
...@@ -134,9 +134,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network ...@@ -134,9 +134,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
if (!disposed) if (!disposed)
{ {
disposed = true; disposed = true;
var b = buffer; bufferPool.ReturnBuffer(buffer);
buffer = null;
bufferPool.ReturnBuffer(b);
} }
} }
} }
......
...@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network ...@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
internal class CustomBufferedStream : Stream, ICustomStreamReader internal class CustomBufferedStream : Stream, ICustomStreamReader
{ {
private readonly bool leaveOpen; private readonly bool leaveOpen;
private byte[] streamBuffer; private readonly byte[] streamBuffer;
// default to UTF-8 // default to UTF-8
private static Encoding encoding => HttpHelper.HeaderEncoding; private static Encoding encoding => HttpHelper.HeaderEncoding;
...@@ -397,9 +397,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network ...@@ -397,9 +397,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
BaseStream.Dispose(); BaseStream.Dispose();
} }
var buffer = streamBuffer; bufferPool.ReturnBuffer(streamBuffer);
streamBuffer = null;
bufferPool.ReturnBuffer(buffer);
} }
} }
...@@ -569,7 +567,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network ...@@ -569,7 +567,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
/// Read a line from the byte stream /// Read a line from the byte stream
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
internal static async Task<string> ReadLineInternalAsync(ICustomStreamReader reader, IBufferPool bufferPool, CancellationToken cancellationToken = default) internal static async Task<string?> ReadLineInternalAsync(ICustomStreamReader reader, IBufferPool bufferPool, CancellationToken cancellationToken = default)
{ {
byte lastChar = default; byte lastChar = default;
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
...@@ -49,7 +49,7 @@ namespace Titanium.Web.Proxy.StreamExtended ...@@ -49,7 +49,7 @@ namespace Titanium.Web.Proxy.StreamExtended
internal int EntensionsStartPosition { get; set; } internal int EntensionsStartPosition { get; set; }
public Dictionary<string, SslExtension> Extensions { get; set; } public Dictionary<string, SslExtension>? Extensions { get; set; }
private static string SslVersionToString(int major, int minor) private static string SslVersionToString(int major, int minor)
{ {
......
...@@ -32,7 +32,7 @@ namespace Titanium.Web.Proxy.StreamExtended ...@@ -32,7 +32,7 @@ namespace Titanium.Web.Proxy.StreamExtended
/// <param name="bufferPool"></param> /// <param name="bufferPool"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
public static async Task<ClientHelloInfo> PeekClientHello(CustomBufferedStream clientStream, IBufferPool bufferPool, CancellationToken cancellationToken = default) public static async Task<ClientHelloInfo?> PeekClientHello(CustomBufferedStream clientStream, IBufferPool bufferPool, CancellationToken cancellationToken = default)
{ {
// detects the HTTPS ClientHello message as it is described in the following url: // detects the HTTPS ClientHello message as it is described in the following url:
// https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format // https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
...@@ -88,13 +88,12 @@ namespace Titanium.Web.Proxy.StreamExtended ...@@ -88,13 +88,12 @@ namespace Titanium.Web.Proxy.StreamExtended
byte[] sessionId = peekStream.ReadBytes(sessionIdLength); byte[] sessionId = peekStream.ReadBytes(sessionIdLength);
byte[] random = peekStream.ReadBytes(randomLength); byte[] random = peekStream.ReadBytes(randomLength);
var clientHelloInfo = new ClientHelloInfo var clientHelloInfo = new ClientHelloInfo(sessionId)
{ {
HandshakeVersion = 2, HandshakeVersion = 2,
MajorVersion = majorVersion, MajorVersion = majorVersion,
MinorVersion = minorVersion, MinorVersion = minorVersion,
Random = random, Random = random,
SessionId = sessionId,
Ciphers = ciphers, Ciphers = ciphers,
ClientHelloLength = peekStream.Position, ClientHelloLength = peekStream.Position,
}; };
...@@ -171,20 +170,19 @@ namespace Titanium.Web.Proxy.StreamExtended ...@@ -171,20 +170,19 @@ namespace Titanium.Web.Proxy.StreamExtended
int extenstionsStartPosition = peekStream.Position; int extenstionsStartPosition = peekStream.Position;
Dictionary<string, SslExtension> extensions = null; Dictionary<string, SslExtension>? extensions = null;
if(extenstionsStartPosition < recordLength + 5) if(extenstionsStartPosition < recordLength + 5)
{ {
extensions = await ReadExtensions(majorVersion, minorVersion, peekStream, bufferPool, cancellationToken); extensions = await ReadExtensions(majorVersion, minorVersion, peekStream, bufferPool, cancellationToken);
} }
var clientHelloInfo = new ClientHelloInfo var clientHelloInfo = new ClientHelloInfo(sessionId)
{ {
HandshakeVersion = 3, HandshakeVersion = 3,
MajorVersion = majorVersion, MajorVersion = majorVersion,
MinorVersion = minorVersion, MinorVersion = minorVersion,
Random = random, Random = random,
SessionId = sessionId,
Ciphers = ciphers, Ciphers = ciphers,
CompressionData = compressionData, CompressionData = compressionData,
ClientHelloLength = peekStream.Position, ClientHelloLength = peekStream.Position,
...@@ -218,7 +216,7 @@ namespace Titanium.Web.Proxy.StreamExtended ...@@ -218,7 +216,7 @@ namespace Titanium.Web.Proxy.StreamExtended
/// <param name="bufferPool"></param> /// <param name="bufferPool"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
public static async Task<ServerHelloInfo> PeekServerHello(CustomBufferedStream serverStream, IBufferPool bufferPool, CancellationToken cancellationToken = default) public static async Task<ServerHelloInfo?> PeekServerHello(CustomBufferedStream serverStream, IBufferPool bufferPool, CancellationToken cancellationToken = default)
{ {
// detects the HTTPS ClientHello message as it is described in the following url: // detects the HTTPS ClientHello message as it is described in the following url:
// https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format // https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
...@@ -324,7 +322,7 @@ namespace Titanium.Web.Proxy.StreamExtended ...@@ -324,7 +322,7 @@ namespace Titanium.Web.Proxy.StreamExtended
int extenstionsStartPosition = peekStream.Position; int extenstionsStartPosition = peekStream.Position;
Dictionary<string, SslExtension> extensions = null; Dictionary<string, SslExtension>? extensions = null;
if (extenstionsStartPosition < recordLength + 5) if (extenstionsStartPosition < recordLength + 5)
{ {
...@@ -351,9 +349,9 @@ namespace Titanium.Web.Proxy.StreamExtended ...@@ -351,9 +349,9 @@ namespace Titanium.Web.Proxy.StreamExtended
return null; return null;
} }
private static async Task<Dictionary<string, SslExtension>> ReadExtensions(int majorVersion, int minorVersion, CustomBufferedPeekStream peekStream, IBufferPool bufferPool, CancellationToken cancellationToken) private static async Task<Dictionary<string, SslExtension>?> ReadExtensions(int majorVersion, int minorVersion, CustomBufferedPeekStream peekStream, IBufferPool bufferPool, CancellationToken cancellationToken)
{ {
Dictionary<string, SslExtension> extensions = null; Dictionary<string, SslExtension>? extensions = null;
if (majorVersion > 3 || majorVersion == 3 && minorVersion >= 1) if (majorVersion > 3 || majorVersion == 3 && minorVersion >= 1)
{ {
if (await peekStream.EnsureBufferLength(2, cancellationToken)) if (await peekStream.EnsureBufferLength(2, cancellationToken))
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net;
using System.Net.Security; using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Authentication; using System.Security.Authentication;
...@@ -35,23 +36,19 @@ namespace Titanium.Web.Proxy ...@@ -35,23 +36,19 @@ namespace Titanium.Web.Proxy
var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferPool); var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferPool);
var clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool); var clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool);
SslStream sslStream = null; SslStream? sslStream = null;
try try
{ {
var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken); var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken);
bool isHttps = clientHelloInfo != null; string? httpsHostName = null;
string httpsHostName = null;
if (isHttps) if (clientHelloInfo != null)
{ {
httpsHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName; httpsHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName;
var args = new BeforeSslAuthenticateEventArgs(cancellationTokenSource) var args = new BeforeSslAuthenticateEventArgs(cancellationTokenSource, httpsHostName);
{
SniHostName = httpsHostName
};
await endPoint.InvokeBeforeSslAuthenticate(this, args, ExceptionFunc); await endPoint.InvokeBeforeSslAuthenticate(this, args, ExceptionFunc);
...@@ -65,7 +62,7 @@ namespace Titanium.Web.Proxy ...@@ -65,7 +62,7 @@ namespace Titanium.Web.Proxy
clientConnection.SslProtocol = clientHelloInfo.SslProtocol; clientConnection.SslProtocol = clientHelloInfo.SslProtocol;
// do client authentication using certificate // do client authentication using certificate
X509Certificate2 certificate = null; X509Certificate2? certificate = null;
try try
{ {
sslStream = new SslStream(clientStream, false); sslStream = new SslStream(clientStream, false);
...@@ -98,7 +95,7 @@ namespace Titanium.Web.Proxy ...@@ -98,7 +95,7 @@ namespace Titanium.Web.Proxy
else else
{ {
var connection = await tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port, var connection = await tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port,
httpVersion: null, isHttps: false, applicationProtocols: null, httpVersion: HttpHeader.VersionUnknown, isHttps: false, applicationProtocols: null,
isConnect: true, proxyServer: this, session:null, upStreamEndPoint: UpStreamEndPoint, isConnect: true, proxyServer: this, session:null, upStreamEndPoint: UpStreamEndPoint,
externalProxy: UpStreamHttpsProxy, noCache: true, cancellationToken: cancellationToken); externalProxy: UpStreamHttpsProxy, noCache: true, cancellationToken: cancellationToken);
...@@ -136,10 +133,11 @@ namespace Titanium.Web.Proxy ...@@ -136,10 +133,11 @@ namespace Titanium.Web.Proxy
return; return;
} }
} }
// HTTPS server created - we can now decrypt the client's traffic // HTTPS server created - we can now decrypt the client's traffic
// Now create the request // Now create the request
await handleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter, await handleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter,
cancellationTokenSource, isHttps ? httpsHostName : null, null, null); cancellationTokenSource, httpsHostName, null, null);
} }
catch (ProxyException e) catch (ProxyException e)
{ {
......
...@@ -47,8 +47,8 @@ namespace Titanium.Web.Proxy ...@@ -47,8 +47,8 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
private async Task handle401UnAuthorized(SessionEventArgs args) private async Task handle401UnAuthorized(SessionEventArgs args)
{ {
string headerName = null; string? headerName = null;
HttpHeader authHeader = null; HttpHeader? authHeader = null;
var response = args.HttpClient.Response; var response = args.HttpClient.Response;
...@@ -91,7 +91,7 @@ namespace Titanium.Web.Proxy ...@@ -91,7 +91,7 @@ namespace Titanium.Web.Proxy
if (authHeader != null) if (authHeader != null)
{ {
string scheme = authSchemes.Contains(authHeader.Value) ? authHeader.Value : null; string? scheme = authSchemes.Contains(authHeader.Value) ? authHeader.Value : null;
var expectedAuthState = var expectedAuthState =
scheme == null ? State.WinAuthState.INITIAL_TOKEN : State.WinAuthState.UNAUTHORIZED; scheme == null ? State.WinAuthState.INITIAL_TOKEN : State.WinAuthState.UNAUTHORIZED;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment