Commit 9df31edd authored by Honfika's avatar Honfika

Nullable reference fixes

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