Unverified Commit 7a44e456 authored by honfika's avatar honfika Committed by GitHub

Merge pull request #348 from justcoding121/develop

beta|develop
parents 83377610 46a0b972
......@@ -28,8 +28,7 @@ namespace Titanium.Web.Proxy.Examples.Basic.Helpers
var consoleHandle = GetStdHandle(STD_INPUT_HANDLE);
// get current console mode
uint consoleMode;
if (!GetConsoleMode(consoleHandle, out consoleMode))
if (!GetConsoleMode(consoleHandle, out uint consoleMode))
{
// ERROR: Unable to get console mode.
return false;
......
......@@ -28,7 +28,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
public SessionListItem SelectedSession
{
get { return selectedSession; }
get => selectedSession;
set
{
if (value != selectedSession)
......@@ -44,8 +44,8 @@ namespace Titanium.Web.Proxy.Examples.Wpf
public int ClientConnectionCount
{
get { return (int)GetValue(ClientConnectionCountProperty); }
set { SetValue(ClientConnectionCountProperty, value); }
get => (int)GetValue(ClientConnectionCountProperty);
set => SetValue(ClientConnectionCountProperty, value);
}
public static readonly DependencyProperty ServerConnectionCountProperty = DependencyProperty.Register(
......@@ -53,8 +53,8 @@ namespace Titanium.Web.Proxy.Examples.Wpf
public int ServerConnectionCount
{
get { return (int)GetValue(ServerConnectionCountProperty); }
set { SetValue(ServerConnectionCountProperty, value); }
get => (int)GetValue(ServerConnectionCountProperty);
set => SetValue(ServerConnectionCountProperty, value);
}
private readonly Dictionary<HttpWebClient, SessionListItem> sessionDictionary = new Dictionary<HttpWebClient, SessionListItem>();
......@@ -107,8 +107,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
{
await Dispatcher.InvokeAsync(() =>
{
SessionListItem item;
if (sessionDictionary.TryGetValue(e.WebSession, out item))
if (sessionDictionary.TryGetValue(e.WebSession, out var item))
{
item.Update();
}
......@@ -135,8 +134,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
SessionListItem item = null;
await Dispatcher.InvokeAsync(() =>
{
SessionListItem item2;
if (sessionDictionary.TryGetValue(e.WebSession, out item2))
if (sessionDictionary.TryGetValue(e.WebSession, out var item2))
{
item2.Update();
item = item2;
......@@ -177,8 +175,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
e.DataReceived += (sender, args) =>
{
var session = (SessionEventArgs)sender;
SessionListItem li;
if (sessionDictionary.TryGetValue(session.WebSession, out li))
if (sessionDictionary.TryGetValue(session.WebSession, out var li))
{
li.ReceivedDataCount += args.Count;
}
......@@ -187,8 +184,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
e.DataSent += (sender, args) =>
{
var session = (SessionEventArgs)sender;
SessionListItem li;
if (sessionDictionary.TryGetValue(session.WebSession, out li))
if (sessionDictionary.TryGetValue(session.WebSession, out var li))
{
li.SentDataCount += args.Count;
}
......
......@@ -26,50 +26,50 @@ namespace Titanium.Web.Proxy.Examples.Wpf
public string StatusCode
{
get { return statusCode; }
set { SetField(ref statusCode, value);}
get => statusCode;
set => SetField(ref statusCode, value);
}
public string Protocol
{
get { return protocol; }
set { SetField(ref protocol, value); }
get => protocol;
set => SetField(ref protocol, value);
}
public string Host
{
get { return host; }
set { SetField(ref host, value); }
get => host;
set => SetField(ref host, value);
}
public string Url
{
get { return url; }
set { SetField(ref url, value); }
get => url;
set => SetField(ref url, value);
}
public long BodySize
{
get { return bodySize; }
set { SetField(ref bodySize, value); }
get => bodySize;
set => SetField(ref bodySize, value);
}
public string Process
{
get { return process; }
set { SetField(ref process, value); }
get => process;
set => SetField(ref process, value);
}
public long ReceivedDataCount
{
get { return receivedDataCount; }
set { SetField(ref receivedDataCount, value); }
get => receivedDataCount;
set => SetField(ref receivedDataCount, value);
}
public long SentDataCount
{
get { return sentDataCount; }
set { SetField(ref sentDataCount, value); }
get => sentDataCount;
set => SetField(ref sentDataCount, value);
}
public event PropertyChangedEventHandler PropertyChanged;
......
......@@ -51,8 +51,8 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="StreamExtended, Version=1.0.81.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL">
<HintPath>..\..\packages\StreamExtended.1.0.81\lib\net45\StreamExtended.dll</HintPath>
<Reference Include="StreamExtended, Version=1.0.110.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL">
<HintPath>..\..\packages\StreamExtended.1.0.110-beta\lib\net45\StreamExtended.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
......
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="StreamExtended" version="1.0.81" targetFramework="net45" />
<package id="StreamExtended" version="1.0.110-beta" targetFramework="net45" />
</packages>
\ No newline at end of file
using System;
using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.EventArguments
{
public class MultipartRequestPartSentEventArgs : EventArgs
{
public string Boundary { get; }
public HeaderCollection Headers { get; }
public MultipartRequestPartSentEventArgs(string boundary, HeaderCollection headers)
{
Boundary = boundary;
Headers = headers;
}
}
}
\ No newline at end of file
......@@ -4,7 +4,6 @@ using System.IO;
using System.Net;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Decompression;
using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
......@@ -42,6 +41,8 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
internal ProxyClient ProxyClient { get; set; }
internal bool HasMulipartEventSubscribers => MultipartRequestPartSent != null;
/// <summary>
/// Returns a unique Id for this request/response session
/// same as RequestId of WebSession
......@@ -53,7 +54,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
public bool ReRequest
{
get { return reRequest; }
get => reRequest;
set
{
if (WebSession.Response.StatusCode == 0)
......@@ -90,6 +91,11 @@ namespace Titanium.Web.Proxy.EventArguments
public event EventHandler<DataEventArgs> DataReceived;
/// <summary>
/// Occurs when multipart request part sent.
/// </summary>
public event EventHandler<MultipartRequestPartSentEventArgs> MultipartRequestPartSent;
public ProxyEndPoint LocalEndPoint;
/// <summary>
......@@ -189,6 +195,11 @@ namespace Titanium.Web.Proxy.EventArguments
DataReceived?.Invoke(this, new DataEventArgs(buffer, offset, count));
}
internal void OnMultipartRequestPartSent(string boundary, HeaderCollection headers)
{
MultipartRequestPartSent?.Invoke(this, new MultipartRequestPartSentEventArgs(boundary, headers));
}
/// <summary>
/// Read response body as byte[] for current response
/// </summary>
......
using System.Net;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.EventArguments
......
using System.Text;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Extensions
{
/// <summary>
/// Extensions on HttpWebSession object
/// </summary>
internal static class HttpWebRequestExtensions
{
/// <summary>
/// parse the character encoding of request from request headers
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
internal static Encoding GetEncoding(this Request request)
{
return HttpHelper.GetEncodingFromContentType(request.ContentType);
}
}
}
using System.Text;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Extensions
{
internal static class HttpWebResponseExtensions
{
/// <summary>
/// Gets the character encoding of response from response headers
/// </summary>
/// <param name="response"></param>
/// <returns></returns>
internal static Encoding GetResponseCharacterEncoding(this Response response)
{
return HttpHelper.GetEncodingFromContentType(response.ContentType);
}
}
}
using StreamExtended.Network;
using System;
using System;
using System.Globalization;
using System.IO;
using System.Threading.Tasks;
using StreamExtended.Network;
namespace Titanium.Web.Proxy.Extensions
{
......@@ -17,6 +17,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="input"></param>
/// <param name="output"></param>
/// <param name="onCopy"></param>
/// <param name="bufferSize"></param>
internal static async Task CopyToAsync(this Stream input, Stream output, Action<byte[], int, int> onCopy, int bufferSize)
{
byte[] buffer = new byte[bufferSize];
......
using System.Net.Sockets;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy.Extensions
{
......
......@@ -8,7 +8,12 @@ namespace Titanium.Web.Proxy.Helpers
{
private static readonly Encoding defaultEncoding = Encoding.GetEncoding("ISO-8859-1");
public static Encoding GetEncodingFromContentType(string contentType)
/// <summary>
/// Gets the character encoding of request/response from content-type header
/// </summary>
/// <param name="contentType"></param>
/// <returns></returns>
internal static Encoding GetEncodingFromContentType(string contentType)
{
try
{
......@@ -22,10 +27,10 @@ namespace Titanium.Web.Proxy.Helpers
var parameters = contentType.Split(ProxyConstants.SemiColonSplit);
foreach (string parameter in parameters)
{
var encodingSplit = parameter.Split(ProxyConstants.EqualSplit, 2);
if (encodingSplit.Length == 2 && encodingSplit[0].Trim().Equals("charset", StringComparison.CurrentCultureIgnoreCase))
var split = parameter.Split(ProxyConstants.EqualSplit, 2);
if (split.Length == 2 && split[0].Trim().Equals("charset", StringComparison.CurrentCultureIgnoreCase))
{
string value = encodingSplit[1];
string value = split[1];
if (value.Equals("x-user-defined", StringComparison.OrdinalIgnoreCase))
{
//todo: what is this?
......@@ -51,6 +56,32 @@ namespace Titanium.Web.Proxy.Helpers
return defaultEncoding;
}
internal static string GetBoundaryFromContentType(string contentType)
{
if (contentType != null)
{
//extract the boundary
var parameters = contentType.Split(ProxyConstants.SemiColonSplit);
foreach (string parameter in parameters)
{
var split = parameter.Split(ProxyConstants.EqualSplit, 2);
if (split.Length == 2 && split[0].Trim().Equals("boundary", StringComparison.CurrentCultureIgnoreCase))
{
string value = split[1];
if (value.Length > 2 && value[0] == '"' && value[value.Length - 1] == '"')
{
value = value.Substring(1, value.Length - 2);
}
return value;
}
}
}
//return null if not specified
return null;
}
/// <summary>
/// Tries to get root domain from a given hostname
/// Adapted from below answer
......
using StreamExtended.Network;
using System;
using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using StreamExtended.Network;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Shared;
......
......@@ -54,9 +54,7 @@ namespace Titanium.Web.Proxy.Helpers
{
localhost = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress;
if (IPAddress.TryParse(hostName, out ipAddress))
if (IPAddress.TryParse(hostName, out var ipAddress))
isLocalhost = localhost.AddressList.Any(x => x.Equals(ipAddress));
if (!isLocalhost)
......
......@@ -81,8 +81,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
public ExternalProxy GetProxy(Uri destination)
{
IList<string> proxies;
if (GetAutoProxies(destination, out proxies))
if (GetAutoProxies(destination, out var proxies))
{
if (proxies == null)
{
......
......@@ -227,8 +227,7 @@ namespace Titanium.Web.Proxy.Http
internal string GetHeaderValueOrNull(string headerName)
{
HttpHeader header;
if (Headers.TryGetValue(headerName, out header))
if (Headers.TryGetValue(headerName, out var header))
{
return header.Value;
}
......@@ -238,8 +237,7 @@ namespace Titanium.Web.Proxy.Http
internal string SetOrAddHeaderValue(string headerName, string value)
{
HttpHeader header;
if (Headers.TryGetValue(headerName, out header))
if (Headers.TryGetValue(headerName, out var header))
{
header.Value = value;
}
......
using StreamExtended.Network;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using StreamExtended.Network;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Shared;
......@@ -25,7 +26,7 @@ namespace Titanium.Web.Proxy.Http
{
nonUniqueResponseHeaders[newHeader.Name].Add(newHeader);
}
//if header is alread in unique header collection then move both to non-unique collection
//if header is already in unique header collection then move both to non-unique collection
else if (headers.ContainsKey(newHeader.Name))
{
var existing = headers[newHeader.Name];
......@@ -46,5 +47,17 @@ namespace Titanium.Web.Proxy.Http
}
}
}
/// <summary>
/// Increase size of buffer and copy existing content to new buffer
/// </summary>
/// <param name="buffer"></param>
/// <param name="size"></param>
private static void ResizeBuffer(ref byte[] buffer, long size)
{
var newBuffer = new byte[size];
Buffer.BlockCopy(buffer, 0, newBuffer, 0, buffer.Length);
buffer = newBuffer;
}
}
}
......@@ -136,10 +136,7 @@ namespace Titanium.Web.Proxy.Http
{
string httpStatus = await ServerConnection.StreamReader.ReadLineAsync();
Version version;
int responseStatusCode;
string responseStatusDescription;
Response.ParseResponseLine(httpStatus, out version, out responseStatusCode, out responseStatusDescription);
Response.ParseResponseLine(httpStatus, out _, out int responseStatusCode, out string responseStatusDescription);
//find if server is willing for expect continue
if (responseStatusCode == (int)HttpStatusCode.Continue
......@@ -180,10 +177,7 @@ namespace Titanium.Web.Proxy.Http
httpStatus = await ServerConnection.StreamReader.ReadLineAsync();
}
Version version;
int statusCode;
string statusDescription;
Response.ParseResponseLine(httpStatus, out version, out statusCode, out statusDescription);
Response.ParseResponseLine(httpStatus, out var version, out int statusCode, out string statusDescription);
Response.HttpVersion = version;
Response.StatusCode = statusCode;
......
......@@ -3,6 +3,7 @@ using System.ComponentModel;
using System.Text;
using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Shared;
......@@ -66,14 +67,8 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public string Host
{
get
{
return Headers.GetHeaderValueOrNull("host");
}
set
{
Headers.SetOrAddHeaderValue("host", value);
}
get => Headers.GetHeaderValueOrNull("host");
set => Headers.SetOrAddHeaderValue("host", value);
}
/// <summary>
......@@ -95,8 +90,7 @@ namespace Titanium.Web.Proxy.Http
return -1;
}
long contentLen;
long.TryParse(headerValue, out contentLen);
long.TryParse(headerValue, out long contentLen);
if (contentLen >= 0)
{
return contentLen;
......@@ -123,14 +117,8 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public string ContentType
{
get
{
return Headers.GetHeaderValueOrNull("content-type");
}
set
{
Headers.SetOrAddHeaderValue("content-type", value);
}
get => Headers.GetHeaderValueOrNull("content-type");
set => Headers.SetOrAddHeaderValue("content-type", value);
}
/// <summary>
......@@ -169,6 +157,8 @@ namespace Titanium.Web.Proxy.Http
}
}
public bool IsMultipartFormData => ContentType?.StartsWith("multipart/form-data") == true;
/// <summary>
/// Request Url
/// </summary>
......@@ -177,7 +167,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// Encoding for this request
/// </summary>
public Encoding Encoding => this.GetEncoding();
public Encoding Encoding => HttpHelper.GetEncodingFromContentType(ContentType);
/// <summary>
/// Terminates the underlying Tcp Connection to client after current request
......
......@@ -2,6 +2,7 @@
using System.ComponentModel;
using System.Text;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Shared;
......@@ -36,7 +37,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// Encoding used in response
/// </summary>
public Encoding Encoding => this.GetResponseCharacterEncoding();
public Encoding Encoding => HttpHelper.GetEncodingFromContentType(ContentType);
/// <summary>
/// Content encoding for this response
......@@ -118,8 +119,7 @@ namespace Titanium.Web.Proxy.Http
return -1;
}
long contentLen;
long.TryParse(headerValue, out contentLen);
long.TryParse(headerValue, out long contentLen);
if (contentLen >= 0)
{
return contentLen;
......
......@@ -28,7 +28,7 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public string UserName
{
get { return UseDefaultCredentials ? defaultCredentials.Value.UserName : userName; }
get => UseDefaultCredentials ? defaultCredentials.Value.UserName : userName;
set
{
userName = value;
......@@ -45,7 +45,7 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public string Password
{
get { return UseDefaultCredentials ? defaultCredentials.Value.Password : password; }
get => UseDefaultCredentials ? defaultCredentials.Value.Password : password;
set
{
password = value;
......
using System;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using Org.BouncyCastle.Asn1;
......
......@@ -7,7 +7,6 @@ using System.Linq;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Network.Certificate;
......@@ -36,7 +35,7 @@ namespace Titanium.Web.Proxy.Network
{
internal CertificateEngine Engine
{
get { return engine; }
get => engine;
set
{
//For Mono (or Non-Windows) only Bouncy Castle is supported
......@@ -83,7 +82,7 @@ namespace Titanium.Web.Proxy.Network
internal string Issuer
{
get { return issuer ?? defaultRootCertificateIssuer; }
get => issuer ?? defaultRootCertificateIssuer;
set
{
issuer = value;
......@@ -93,7 +92,7 @@ namespace Titanium.Web.Proxy.Network
internal string RootCertificateName
{
get { return rootCertificateName ?? defaultRootRootCertificateName; }
get => rootCertificateName ?? defaultRootRootCertificateName;
set
{
rootCertificateName = value;
......@@ -103,7 +102,7 @@ namespace Titanium.Web.Proxy.Network
internal X509Certificate2 RootCertificate
{
get { return rootCertificate; }
get => rootCertificate;
set
{
ClearRootCertificate();
......
......@@ -2,7 +2,6 @@
using System;
using System.Net;
using System.Net.Sockets;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Network.Tcp
......
......@@ -5,7 +5,6 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
......
using StreamExtended.Network;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
......@@ -8,8 +7,8 @@ using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended.Network;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Helpers.WinHttp;
using Titanium.Web.Proxy.Models;
......@@ -84,8 +83,8 @@ namespace Titanium.Web.Proxy
/// </summary>
public X509Certificate2 RootCertificate
{
get { return CertificateManager.RootCertificate; }
set { CertificateManager.RootCertificate = value; }
get => CertificateManager.RootCertificate;
set => CertificateManager.RootCertificate = value;
}
/// <summary>
......@@ -94,8 +93,8 @@ namespace Titanium.Web.Proxy
/// </summary>
public string RootCertificateIssuerName
{
get { return CertificateManager.Issuer; }
set { CertificateManager.Issuer = value; }
get => CertificateManager.Issuer;
set => CertificateManager.Issuer = value;
}
/// <summary>
......@@ -107,8 +106,8 @@ namespace Titanium.Web.Proxy
/// </summary>
public string RootCertificateName
{
get { return CertificateManager.RootCertificateName; }
set { CertificateManager.RootCertificateName = value; }
get => CertificateManager.RootCertificateName;
set => CertificateManager.RootCertificateName = value;
}
/// <summary>
......@@ -118,7 +117,7 @@ namespace Titanium.Web.Proxy
/// </summary>
public bool TrustRootCertificate
{
get { return trustRootCertificate; }
get => trustRootCertificate;
set
{
trustRootCertificate = value;
......@@ -136,8 +135,8 @@ namespace Titanium.Web.Proxy
/// </summary>
public CertificateEngine CertificateEngine
{
get { return CertificateManager.Engine; }
set { CertificateManager.Engine = value; }
get => CertificateManager.Engine;
set => CertificateManager.Engine = value;
}
/// <summary>
......@@ -242,8 +241,8 @@ namespace Titanium.Web.Proxy
/// </summary>
public Action<Exception> ExceptionFunc
{
get { return exceptionFunc ?? defaultExceptionFunc.Value; }
set { exceptionFunc = value; }
get => exceptionFunc ?? defaultExceptionFunc.Value;
set => exceptionFunc = value;
}
/// <summary>
......
using StreamExtended;
using StreamExtended.Network;
using System;
using System;
using System.IO;
using System.Linq;
using System.Net;
......@@ -8,12 +6,16 @@ using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Threading.Tasks;
using StreamExtended;
using StreamExtended.Helpers;
using StreamExtended.Network;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network;
using Titanium.Web.Proxy.Network.Tcp;
namespace Titanium.Web.Proxy
......@@ -53,10 +55,7 @@ namespace Titanium.Web.Proxy
return;
}
string httpMethod;
string httpUrl;
Version version;
Request.ParseRequestLine(httpCmd, out httpMethod, out httpUrl, out version);
Request.ParseRequestLine(httpCmd, out string httpMethod, out string httpUrl, out var version);
httpRemoteUri = httpMethod == "CONNECT" ? new Uri("http://" + httpUrl) : new Uri(httpUrl);
......@@ -236,7 +235,12 @@ namespace Titanium.Web.Proxy
var sslStream = new SslStream(clientStream);
clientStream = new CustomBufferedStream(sslStream, BufferSize);
string sniHostName = clientSslHelloInfo.Extensions?.FirstOrDefault(x => x.Name == "server_name")?.Data;
string sniHostName = null;
if (clientSslHelloInfo.Extensions != null && clientSslHelloInfo.Extensions.TryGetValue("server_name", out var serverNameExtension))
{
sniHostName = serverNameExtension.Data;
}
string certName = HttpHelper.GetWildCardDomainName(sniHostName ?? endPoint.GenericCertificateName);
var certificate = CertificateManager.CreateCertificate(certName, false);
......@@ -306,10 +310,7 @@ namespace Titanium.Web.Proxy
try
{
string httpMethod;
string httpUrl;
Version version;
Request.ParseRequestLine(httpCmd, out httpMethod, out httpUrl, out version);
Request.ParseRequestLine(httpCmd, out string httpMethod, out string httpUrl, out var version);
//Read the request headers in to unique and non-unique header collections
await HeaderParser.ReadHeaders(clientStreamReader, args.WebSession.Request.Headers);
......@@ -390,10 +391,7 @@ namespace Titanium.Web.Proxy
await connection.Stream.WriteAsync(requestBytes, 0, requestBytes.Length);
string httpStatus = await connection.StreamReader.ReadLineAsync();
Version responseVersion;
int responseStatusCode;
string responseStatusDescription;
Response.ParseResponseLine(httpStatus, out responseVersion, out responseStatusCode, out responseStatusDescription);
Response.ParseResponseLine(httpStatus, out var responseVersion, out int responseStatusCode, out string responseStatusDescription);
args.WebSession.Response.HttpVersion = responseVersion;
args.WebSession.Response.StatusCode = responseStatusCode;
args.WebSession.Response.StatusDescription = responseStatusDescription;
......@@ -466,11 +464,12 @@ namespace Titanium.Web.Proxy
try
{
args.WebSession.Request.RequestLocked = true;
var request = args.WebSession.Request;
request.RequestLocked = true;
//if expect continue is enabled then send the headers first
//and see if server would return 100 conitinue
if (args.WebSession.Request.ExpectContinue)
if (request.ExpectContinue)
{
args.WebSession.SetConnection(connection);
await args.WebSession.SendRequest(Enable100ContinueBehaviour);
......@@ -479,12 +478,12 @@ namespace Titanium.Web.Proxy
//If 100 continue was the response inform that to the client
if (Enable100ContinueBehaviour)
{
if (args.WebSession.Request.Is100Continue)
if (request.Is100Continue)
{
await args.ProxyClient.ClientStreamWriter.WriteResponseStatusAsync(args.WebSession.Response.HttpVersion, (int)HttpStatusCode.Continue, "Continue");
await args.ProxyClient.ClientStreamWriter.WriteLineAsync();
}
else if (args.WebSession.Request.ExpectationFailed)
else if (request.ExpectationFailed)
{
await args.ProxyClient.ClientStreamWriter.WriteResponseStatusAsync(args.WebSession.Response.HttpVersion, (int)HttpStatusCode.ExpectationFailed, "Expectation Failed");
await args.ProxyClient.ClientStreamWriter.WriteLineAsync();
......@@ -492,38 +491,37 @@ namespace Titanium.Web.Proxy
}
//If expect continue is not enabled then set the connectio and send request headers
if (!args.WebSession.Request.ExpectContinue)
if (!request.ExpectContinue)
{
args.WebSession.SetConnection(connection);
await args.WebSession.SendRequest(Enable100ContinueBehaviour);
}
//check if content-length is > 0
if (args.WebSession.Request.ContentLength > 0)
if (request.ContentLength > 0)
{
//If request was modified by user
if (args.WebSession.Request.IsBodyRead)
if (request.IsBodyRead)
{
if (args.WebSession.Request.ContentEncoding != null)
if (request.ContentEncoding != null)
{
args.WebSession.Request.Body =
await GetCompressedResponseBody(args.WebSession.Request.ContentEncoding, args.WebSession.Request.Body);
request.Body = await GetCompressedResponseBody(request.ContentEncoding, request.Body);
}
var body = args.WebSession.Request.Body;
var body = request.Body;
//chunked send is not supported as of now
args.WebSession.Request.ContentLength = body.Length;
request.ContentLength = body.Length;
var newStream = args.WebSession.ServerConnection.Stream;
await newStream.WriteAsync(body, 0, body.Length);
}
else
{
if (!args.WebSession.Request.ExpectationFailed)
if (!request.ExpectationFailed)
{
//If its a post/put/patch request, then read the client html body and send it to server
if (args.WebSession.Request.HasBody)
if (request.HasBody)
{
await SendClientRequestBody(args);
}
......@@ -532,7 +530,7 @@ namespace Titanium.Web.Proxy
}
//If not expectation failed response was returned by server then parse response
if (!args.WebSession.Request.ExpectationFailed)
if (!request.ExpectationFailed)
{
disposed = await HandleHttpSessionResponse(args);
......@@ -632,9 +630,36 @@ namespace Titanium.Web.Proxy
//send the request body bytes to server
if (args.WebSession.Request.ContentLength > 0)
{
var request = args.WebSession.Request;
if (args.HasMulipartEventSubscribers && request.IsMultipartFormData)
{
string boundary = HttpHelper.GetBoundaryFromContentType(request.ContentType);
long bytesToSend = args.WebSession.Request.ContentLength;
while (bytesToSend > 0)
{
long read = await SendUntilBoundaryAsync(args.ProxyClient.ClientStream, postStream, bytesToSend, boundary);
if (read == 0)
{
break;
}
bytesToSend -= read;
if (bytesToSend > 0)
{
var headers = new HeaderCollection();
var stream = new CustomBufferedPeekStream(args.ProxyClient.ClientStream);
await HeaderParser.ReadHeaders(new CustomBinaryReader(stream, BufferSize), headers);
args.OnMultipartRequestPartSent(boundary, headers);
}
}
}
else
{
await args.ProxyClient.ClientStreamReader.CopyBytesToStream(postStream, args.WebSession.Request.ContentLength);
}
}
//Need to revist, find any potential bugs
//send the request body bytes to server in chunks
else if (args.WebSession.Request.IsChunked)
......@@ -642,5 +667,68 @@ namespace Titanium.Web.Proxy
await args.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(postStream);
}
}
/// <summary>
/// Read a line from the byte stream
/// </summary>
/// <returns></returns>
public async Task<long> SendUntilBoundaryAsync(CustomBufferedStream inputStream, CustomBufferedStream outputStream, long totalBytesToRead, string boundary)
{
int bufferDataLength = 0;
// try to use the thread static buffer
var buffer = BufferPool.GetBuffer(BufferSize);
int boundaryLength = boundary.Length + 4;
long bytesRead = 0;
while (bytesRead < totalBytesToRead && (inputStream.DataAvailable || await inputStream.FillBufferAsync()))
{
byte newChar = inputStream.ReadByteFromBuffer();
buffer[bufferDataLength] = newChar;
bufferDataLength++;
bytesRead++;
if (bufferDataLength >= boundaryLength)
{
int startIdx = bufferDataLength - boundaryLength;
if (buffer[startIdx] == '-' && buffer[startIdx + 1] == '-'
&& buffer[bufferDataLength - 2] == '\r' && buffer[bufferDataLength - 1] == '\n')
{
startIdx += 2;
bool ok = true;
for (int i = 0; i < boundary.Length; i++)
{
if (buffer[startIdx + i] != boundary[i])
{
ok = false;
break;
}
}
if (ok)
{
break;
}
}
}
if (bufferDataLength == buffer.Length)
{
//boundary is not longer than 70 bytes accounrding to the specification, so keeping the last 100 (minimum 74) bytes is enough
const int bytesToKeep = 100;
await outputStream.WriteAsync(buffer, 0, buffer.Length - bytesToKeep);
Buffer.BlockCopy(buffer, buffer.Length - bytesToKeep, buffer, 0, bytesToKeep);
bufferDataLength = bytesToKeep;
}
}
if (bytesRead > 0)
{
await outputStream.WriteAsync(buffer, 0, bufferDataLength);
}
return bytesRead;
}
}
}
......@@ -13,7 +13,7 @@
<ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.8.1.3" />
<PackageReference Include="StreamExtended" Version="1.0.81" />
<PackageReference Include="StreamExtended" Version="1.0.110-beta" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
......
......@@ -14,7 +14,7 @@
<copyright>Copyright &#x00A9; Titanium. All rights reserved.</copyright>
<tags></tags>
<dependencies>
<dependency id="StreamExtended" version="1.0.81" />
<dependency id="StreamExtended" version="1.0.110-beta" />
<dependency id="Portable.BouncyCastle" version="1.8.1.3" />
</dependencies>
</metadata>
......
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Portable.BouncyCastle" version="1.8.1.3" targetFramework="net45" />
<package id="StreamExtended" version="1.0.81" targetFramework="net45" />
<package id="StreamExtended" version="1.0.110-beta" targetFramework="net45" />
</packages>
\ No newline at end of file
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