Skip to content
This repository was archived by the owner on Jul 9, 2023. It is now read-only.

Linux/Unix new line issue fix #485

Merged
merged 11 commits into from
Aug 23, 2018
Merged
6 changes: 3 additions & 3 deletions Titanium.Web.Proxy/Helpers/HttpWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal class HttpWriter : ICustomStreamWriter
private readonly Stream stream;
private readonly IBufferPool bufferPool;

private static readonly byte[] newLine = ProxyConstants.NewLine;
private static readonly byte[] newLine = ProxyConstants.NewLineBytes;

private static readonly Encoder encoder = Encoding.ASCII.GetEncoder();

Expand Down Expand Up @@ -109,9 +109,9 @@ internal async Task WriteHeadersAsync(HeaderCollection headers, bool flush = tru
var headerBuilder = new StringBuilder();
foreach (var header in headers)
{
headerBuilder.AppendLine(header.ToString());
headerBuilder.Append($"{header.ToString()}{ProxyConstants.NewLine}");
}
headerBuilder.AppendLine();
headerBuilder.Append(ProxyConstants.NewLine);

await WriteAsync(headerBuilder.ToString(), cancellationToken);

Expand Down
12 changes: 7 additions & 5 deletions Titanium.Web.Proxy/Http/HttpWebClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network.Tcp;
using Titanium.Web.Proxy.Shared;

namespace Titanium.Web.Proxy.Http
{
Expand All @@ -16,7 +17,6 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public class HttpWebClient
{

internal HttpWebClient(Request request = null, Response response = null)
{
Request = request ?? new Request();
Expand Down Expand Up @@ -103,26 +103,28 @@ await writer.WriteLineAsync(Request.CreateRequestLine(Request.Method,
Request.HttpVersion), cancellationToken);

var headerBuilder = new StringBuilder();

// Send Authentication to Upstream proxy if needed
if (!isTransparent && upstreamProxy != null
&& ServerConnection.IsHttps == false
&& !string.IsNullOrEmpty(upstreamProxy.UserName)
&& upstreamProxy.Password != null)
{
headerBuilder.AppendLine(HttpHeader.ProxyConnectionKeepAlive.ToString());
headerBuilder.AppendLine(HttpHeader.GetProxyAuthorizationHeader(upstreamProxy.UserName, upstreamProxy.Password).ToString());
headerBuilder.Append($"{HttpHeader.ProxyConnectionKeepAlive}{ProxyConstants.NewLine}");
headerBuilder.Append($"{HttpHeader.GetProxyAuthorizationHeader(upstreamProxy.UserName, upstreamProxy.Password)}{ProxyConstants.NewLine}");
}

// write request headers
foreach (var header in Request.Headers)
{
if (isTransparent || header.Name != KnownHeaders.ProxyAuthorization)
{
headerBuilder.AppendLine(header.ToString());
headerBuilder.Append($"{header}{ProxyConstants.NewLine}");
}
}

headerBuilder.AppendLine();
headerBuilder.Append(ProxyConstants.NewLine);

await writer.WriteAsync(headerBuilder.ToString(), cancellationToken);

if (enable100ContinueBehaviour)
Expand Down
6 changes: 3 additions & 3 deletions Titanium.Web.Proxy/Http/Request.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,13 @@ public override string HeaderText
get
{
var sb = new StringBuilder();
sb.AppendLine(CreateRequestLine(Method, OriginalUrl, HttpVersion));
sb.Append($"{CreateRequestLine(Method, OriginalUrl, HttpVersion)}{ProxyConstants.NewLine}");
foreach (var header in Headers)
{
sb.AppendLine(header.ToString());
sb.Append($"{header.ToString()}{ProxyConstants.NewLine}");
}

sb.AppendLine();
sb.Append(ProxyConstants.NewLine);
return sb.ToString();
}
}
Expand Down
10 changes: 5 additions & 5 deletions Titanium.Web.Proxy/Http/Response.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,13 @@ public override string HeaderText
get
{
var sb = new StringBuilder();
sb.AppendLine(CreateResponseLine(HttpVersion, StatusCode, StatusDescription));
sb.Append($"{CreateResponseLine(HttpVersion, StatusCode, StatusDescription)}{ProxyConstants.NewLine}");
foreach (var header in Headers)
{
sb.AppendLine(header.ToString());
sb.Append($"{header.ToString()}{ProxyConstants.NewLine}");
}

sb.AppendLine();
sb.Append(ProxyConstants.NewLine);
return sb.ToString();
}
}
Expand Down Expand Up @@ -145,7 +145,7 @@ internal static void ParseResponseLine(string httpStatus, out Version version, o
out string statusDescription)
{
var httpResult = httpStatus.Split(ProxyConstants.SpaceSplit, 3);
if (httpResult.Length != 3)
if (httpResult.Length <= 1)
{
throw new Exception("Invalid HTTP status line: " + httpStatus);
}
Expand All @@ -159,7 +159,7 @@ internal static void ParseResponseLine(string httpStatus, out Version version, o
}

statusCode = int.Parse(httpResult[1]);
statusDescription = httpResult[2];
statusDescription = httpResult.Length > 2 ? httpResult[2] : string.Empty;
}
}
}
71 changes: 35 additions & 36 deletions Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ internal class WinCertificateMaker : ICertificateMaker
internal WinCertificateMaker(ExceptionHandler exceptionFunc)
{
this.exceptionFunc = exceptionFunc;

typeX500DN = Type.GetTypeFromProgID("X509Enrollment.CX500DistinguishedName", true);
typeX509PrivateKey = Type.GetTypeFromProgID("X509Enrollment.CX509PrivateKey", true);
typeOID = Type.GetTypeFromProgID("X509Enrollment.CObjectId", true);
Expand All @@ -74,13 +75,41 @@ internal WinCertificateMaker(ExceptionHandler exceptionFunc)
/// <summary>
/// Make certificate.
/// </summary>
/// <param name="sSubjectCN"></param>
/// <param name="isRoot"></param>
/// <param name="signingCert"></param>
/// <returns></returns>
public X509Certificate2 MakeCertificate(string sSubjectCN, bool isRoot, X509Certificate2 signingCert = null)
{
return makeCertificateInternal(sSubjectCN, isRoot, true, signingCert);
return makeCertificate(sSubjectCN, isRoot, true, signingCert);
}

private X509Certificate2 makeCertificate(string sSubjectCN, bool isRoot,
bool switchToMTAIfNeeded, X509Certificate2 signingCert = null,
CancellationToken cancellationToken = default)
{
if (switchToMTAIfNeeded && Thread.CurrentThread.GetApartmentState() != ApartmentState.MTA)
{
return Task.Run(() => makeCertificate(sSubjectCN, isRoot, false, signingCert),
cancellationToken).Result;
}

// Subject
string fullSubject = $"CN={sSubjectCN}";

// Sig Algo
const string hashAlgo = "SHA256";

// Grace Days
const int graceDays = -366;

// ValiDays
const int validDays = 1825;

// KeyLength
const int keyLength = 2048;

var graceTime = DateTime.Now.AddDays(graceDays);
var now = DateTime.Now;
var certificate = makeCertificate(isRoot, sSubjectCN, fullSubject, keyLength, hashAlgo, graceTime,
now.AddDays(validDays), isRoot ? null : signingCert);
return certificate;
}

private X509Certificate2 makeCertificate(bool isRoot, string subject, string fullSubject,
Expand Down Expand Up @@ -271,39 +300,9 @@ private X509Certificate2 makeCertificate(bool isRoot, string subject, string ful

string empty = (string)typeX509Enrollment.InvokeMember("CreatePFX", BindingFlags.InvokeMethod, null,
x509Enrollment, typeValue);

return new X509Certificate2(Convert.FromBase64String(empty), string.Empty, X509KeyStorageFlags.Exportable);
}

private X509Certificate2 makeCertificateInternal(string sSubjectCN, bool isRoot,
bool switchToMTAIfNeeded, X509Certificate2 signingCert = null,
CancellationToken cancellationToken = default)
{
if (switchToMTAIfNeeded && Thread.CurrentThread.GetApartmentState() != ApartmentState.MTA)
{
return Task.Run(() => makeCertificateInternal(sSubjectCN, isRoot, false, signingCert),
cancellationToken).Result;
}

// Subject
string fullSubject = $"CN={sSubjectCN}";

// Sig Algo
const string hashAlgo = "SHA256";

// Grace Days
const int graceDays = -366;

// ValiDays
const int validDays = 1825;

// KeyLength
const int keyLength = 2048;

var graceTime = DateTime.Now.AddDays(graceDays);
var now = DateTime.Now;
var certificate = makeCertificate(isRoot, sSubjectCN, fullSubject, keyLength, hashAlgo, graceTime,
now.AddDays(validDays), isRoot ? null : signingCert);
return certificate;
}
}
}
3 changes: 2 additions & 1 deletion Titanium.Web.Proxy/Network/CertificateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ public enum CertificateEngine
BouncyCastle = 0,

/// <summary>
/// Uses Windows Certification Generation API.
/// Uses Windows Certification Generation API and only valid in Windows OS.
/// Observed to be faster than BouncyCastle.
/// Bug #468 Reported.
/// </summary>
DefaultWindows = 1
Expand Down
18 changes: 5 additions & 13 deletions Titanium.Web.Proxy/RequestHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network.Tcp;
using Titanium.Web.Proxy.Shared;

namespace Titanium.Web.Proxy
{
Expand All @@ -24,15 +25,6 @@ namespace Titanium.Web.Proxy
/// </summary>
public partial class ProxyServer
{
private static readonly Regex uriSchemeRegex =
new Regex("^[a-z]*://", RegexOptions.IgnoreCase | RegexOptions.Compiled);

private static readonly HashSet<string> proxySupportedCompressions =
new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"gzip",
"deflate"
};

private bool isWindowsAuthenticationEnabledAndSupported =>
EnableWinAuth && RunTime.IsWindows && !RunTime.IsRunningOnMono;
Expand Down Expand Up @@ -96,7 +88,7 @@ await HeaderParser.ReadHeaders(clientStream, args.WebSession.Request.Headers,
cancellationToken);

Uri httpRemoteUri;
if (uriSchemeRegex.IsMatch(httpUrl))
if (ProxyConstants.UriSchemeRegex.IsMatch(httpUrl))
{
try
{
Expand Down Expand Up @@ -228,7 +220,7 @@ await handleWebSocketUpgrade(httpCmd, args, request,
}

// construct the web request that we are going to issue on behalf of the client.
await handleHttpSessionRequestInternal(serverConnection, args);
await handleHttpSessionRequest(serverConnection, args);
return true;

}, generator, connection);
Expand Down Expand Up @@ -312,7 +304,7 @@ await tcpConnectionFactory.Release(connection,
/// <param name="serverConnection">The tcp connection.</param>
/// <param name="args">The session event arguments.</param>
/// <returns></returns>
private async Task handleHttpSessionRequestInternal(TcpServerConnection serverConnection, SessionEventArgs args)
private async Task handleHttpSessionRequest(TcpServerConnection serverConnection, SessionEventArgs args)
{
var cancellationToken = args.CancellationTokenSource.Token;
var request = args.WebSession.Request;
Expand Down Expand Up @@ -400,7 +392,7 @@ private void prepareRequestHeaders(HeaderCollection requestHeaders)
//only allow proxy supported compressions
supportedAcceptEncoding.AddRange(acceptEncoding.Split(',')
.Select(x => x.Trim())
.Where(x => proxySupportedCompressions.Contains(x)));
.Where(x => ProxyConstants.ProxySupportedCompressions.Contains(x)));

//uncompressed is always supported by proxy
supportedAcceptEncoding.Add("identity");
Expand Down
2 changes: 1 addition & 1 deletion Titanium.Web.Proxy/ResponseHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ private async Task handleHttpSessionResponse(SessionEventArgs args)
{
// clear current response
await args.ClearResponse(cancellationToken);
await handleHttpSessionRequestInternal(args.WebSession.ServerConnection, args);
await handleHttpSessionRequest(args.WebSession.ServerConnection, args);
return;
}

Expand Down
19 changes: 16 additions & 3 deletions Titanium.Web.Proxy/Shared/ProxyConstants.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Text.RegularExpressions;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace Titanium.Web.Proxy.Shared
{
Expand All @@ -14,9 +16,20 @@ internal class ProxyConstants
internal static readonly char[] SemiColonSplit = { ';' };
internal static readonly char[] EqualSplit = { '=' };

internal static readonly byte[] NewLine = { (byte)'\r', (byte)'\n' };
internal static readonly string NewLine = "\r\n";
internal static readonly byte[] NewLineBytes = { (byte)'\r', (byte)'\n' };

public static readonly Regex CNRemoverRegex =
internal static readonly Regex UriSchemeRegex =
new Regex("^[a-z]*://", RegexOptions.IgnoreCase | RegexOptions.Compiled);

internal static readonly HashSet<string> ProxySupportedCompressions =
new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"gzip",
"deflate"
};

internal static readonly Regex CNRemoverRegex =
new Regex(@"^CN\s*=\s*", RegexOptions.IgnoreCase | RegexOptions.Compiled);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Delegate AsyncEventHandler&lt;TEventArgs&gt;
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.37.2.0">
<meta name="generator" content="docfx 2.38.1.0">

<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class BeforeSslAuthenticateEventArgs
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.37.2.0">
<meta name="generator" content="docfx 2.38.1.0">

<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class CertificateSelectionEventArgs
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.37.2.0">
<meta name="generator" content="docfx 2.38.1.0">

<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class CertificateValidationEventArgs
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.37.2.0">
<meta name="generator" content="docfx 2.38.1.0">

<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class MultipartRequestPartSentEventArgs
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.37.2.0">
<meta name="generator" content="docfx 2.38.1.0">

<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class SessionEventArgs
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.37.2.0">
<meta name="generator" content="docfx 2.38.1.0">

<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class SessionEventArgsBase
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.37.2.0">
<meta name="generator" content="docfx 2.38.1.0">

<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class TunnelConnectSessionEventArgs
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.37.2.0">
<meta name="generator" content="docfx 2.38.1.0">

<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
Expand Down
Loading