Commit 3f66d38c authored by Honfika's avatar Honfika

PROPFIND method is not supported (#367)

parent 788deefa
using System.Globalization; using System;
using System.Globalization;
namespace Titanium.Web.Proxy.Extensions namespace Titanium.Web.Proxy.Extensions
{ {
internal static class StringExtensions internal static class StringExtensions
{ {
internal static bool EqualsIgnoreCase(this string str, string value)
{
return str.Equals(value, StringComparison.CurrentCultureIgnoreCase);
}
internal static bool ContainsIgnoreCase(this string str, string value) internal static bool ContainsIgnoreCase(this string str, string value)
{ {
return CultureInfo.CurrentCulture.CompareInfo.IndexOf(str, value, CompareOptions.IgnoreCase) >= 0; return CultureInfo.CurrentCulture.CompareInfo.IndexOf(str, value, CompareOptions.IgnoreCase) >= 0;
......
using System; using System;
using System.Text; using System.Text;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
...@@ -29,7 +30,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -29,7 +30,7 @@ namespace Titanium.Web.Proxy.Helpers
foreach (string parameter in parameters) foreach (string parameter in parameters)
{ {
var split = parameter.Split(ProxyConstants.EqualSplit, 2); var split = parameter.Split(ProxyConstants.EqualSplit, 2);
if (split.Length == 2 && split[0].Trim().Equals(KnownHeaders.ContentTypeCharset, StringComparison.CurrentCultureIgnoreCase)) if (split.Length == 2 && split[0].Trim().EqualsIgnoreCase(KnownHeaders.ContentTypeCharset))
{ {
string value = split[1]; string value = split[1];
if (value.Equals("x-user-defined", StringComparison.OrdinalIgnoreCase)) if (value.Equals("x-user-defined", StringComparison.OrdinalIgnoreCase))
...@@ -66,7 +67,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -66,7 +67,7 @@ namespace Titanium.Web.Proxy.Helpers
foreach (string parameter in parameters) foreach (string parameter in parameters)
{ {
var split = parameter.Split(ProxyConstants.EqualSplit, 2); var split = parameter.Split(ProxyConstants.EqualSplit, 2);
if (split.Length == 2 && split[0].Trim().Equals(KnownHeaders.ContentTypeBoundary, StringComparison.CurrentCultureIgnoreCase)) if (split.Length == 2 && split[0].Trim().EqualsIgnoreCase(KnownHeaders.ContentTypeBoundary))
{ {
string value = split[1]; string value = split[1];
if (value.Length > 2 && value[0] == '"' && value[value.Length - 1] == '"') if (value.Length > 2 && value[0] == '"' && value[value.Length - 1] == '"')
......
...@@ -36,7 +36,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -36,7 +36,8 @@ namespace Titanium.Web.Proxy.Helpers
try try
{ {
tcpTable = Marshal.AllocHGlobal(tcpTableLength); tcpTable = Marshal.AllocHGlobal(tcpTableLength);
if (NativeMethods.GetExtendedTcpTable(tcpTable, ref tcpTableLength, true, ipVersionValue, (int)NativeMethods.TcpTableType.OwnerPidAll, 0) == 0) if (NativeMethods.GetExtendedTcpTable(tcpTable, ref tcpTableLength, true, ipVersionValue, (int)NativeMethods.TcpTableType.OwnerPidAll, 0) ==
0)
{ {
var table = (NativeMethods.TcpTable)Marshal.PtrToStructure(tcpTable, typeof(NativeMethods.TcpTable)); var table = (NativeMethods.TcpTable)Marshal.PtrToStructure(tcpTable, typeof(NativeMethods.TcpTable));
...@@ -77,7 +78,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -77,7 +78,8 @@ namespace Titanium.Web.Proxy.Helpers
try try
{ {
tcpTable = Marshal.AllocHGlobal(tcpTableLength); tcpTable = Marshal.AllocHGlobal(tcpTableLength);
if (NativeMethods.GetExtendedTcpTable(tcpTable, ref tcpTableLength, true, ipVersionValue, (int)NativeMethods.TcpTableType.OwnerPidAll, 0) == 0) if (NativeMethods.GetExtendedTcpTable(tcpTable, ref tcpTableLength, true, ipVersionValue, (int)NativeMethods.TcpTableType.OwnerPidAll, 0) ==
0)
{ {
var table = (NativeMethods.TcpTable)Marshal.PtrToStructure(tcpTable, typeof(NativeMethods.TcpTable)); var table = (NativeMethods.TcpTable)Marshal.PtrToStructure(tcpTable, typeof(NativeMethods.TcpTable));
...@@ -142,7 +144,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -142,7 +144,8 @@ namespace Titanium.Web.Proxy.Helpers
} }
} }
private static void BeginRead(Stream inputStream, Stream outputStream, byte[] buffer, CancellationTokenSource cts, Action<byte[], int, int> onCopy, Action<Exception> exceptionFunc) private static void BeginRead(Stream inputStream, Stream outputStream, byte[] buffer, CancellationTokenSource cts, Action<byte[], int, int> onCopy,
Action<Exception> exceptionFunc)
{ {
if (cts.IsCancellationRequested) if (cts.IsCancellationRequested)
{ {
...@@ -231,5 +234,27 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -231,5 +234,27 @@ namespace Titanium.Web.Proxy.Helpers
await Task.WhenAll(sendRelay, receiveRelay); await Task.WhenAll(sendRelay, receiveRelay);
} }
/// <summary>
/// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers as prefix
/// Usefull for websocket requests
/// </summary>
/// <param name="clientStream"></param>
/// <param name="serverStream"></param>
/// <param name="bufferSize"></param>
/// <param name="onDataSend"></param>
/// <param name="onDataReceive"></param>
/// <param name="exceptionFunc"></param>
/// <returns></returns>
internal static Task SendRaw(Stream clientStream, Stream serverStream, int bufferSize,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, Action<Exception> exceptionFunc)
{
#if NET45
return SendRawApm(clientStream, serverStream, bufferSize, onDataSend, onDataReceive, exceptionFunc);
#else
// todo: Apm hangs in dotnet core
return SendRawTap(clientStream, serverStream, bufferSize, onDataSend, onDataReceive, exceptionFunc);
#endif
}
} }
} }
\ No newline at end of file
...@@ -2,6 +2,7 @@ using System; ...@@ -2,6 +2,7 @@ using System;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network.Tcp; using Titanium.Web.Proxy.Network.Tcp;
...@@ -123,13 +124,13 @@ namespace Titanium.Web.Proxy.Http ...@@ -123,13 +124,13 @@ namespace Titanium.Web.Proxy.Http
//find if server is willing for expect continue //find if server is willing for expect continue
if (responseStatusCode == (int)HttpStatusCode.Continue if (responseStatusCode == (int)HttpStatusCode.Continue
&& responseStatusDescription.Equals("continue", StringComparison.CurrentCultureIgnoreCase)) && responseStatusDescription.EqualsIgnoreCase("continue"))
{ {
Request.Is100Continue = true; Request.Is100Continue = true;
await ServerConnection.StreamReader.ReadLineAsync(); await ServerConnection.StreamReader.ReadLineAsync();
} }
else if (responseStatusCode == (int)HttpStatusCode.ExpectationFailed else if (responseStatusCode == (int)HttpStatusCode.ExpectationFailed
&& responseStatusDescription.Equals("expectation failed", StringComparison.CurrentCultureIgnoreCase)) && responseStatusDescription.EqualsIgnoreCase("expectation failed"))
{ {
Request.ExpectationFailed = true; Request.ExpectationFailed = true;
await ServerConnection.StreamReader.ReadLineAsync(); await ServerConnection.StreamReader.ReadLineAsync();
...@@ -168,7 +169,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -168,7 +169,7 @@ namespace Titanium.Web.Proxy.Http
//For HTTP 1.1 comptibility server may send expect-continue even if not asked for it in request //For HTTP 1.1 comptibility server may send expect-continue even if not asked for it in request
if (Response.StatusCode == (int)HttpStatusCode.Continue if (Response.StatusCode == (int)HttpStatusCode.Continue
&& Response.StatusDescription.Equals("continue", StringComparison.CurrentCultureIgnoreCase)) && Response.StatusDescription.EqualsIgnoreCase("continue"))
{ {
//Read the next line after 100-continue //Read the next line after 100-continue
Response.Is100Continue = true; Response.Is100Continue = true;
...@@ -181,7 +182,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -181,7 +182,7 @@ namespace Titanium.Web.Proxy.Http
} }
if (Response.StatusCode == (int)HttpStatusCode.ExpectationFailed if (Response.StatusCode == (int)HttpStatusCode.ExpectationFailed
&& Response.StatusDescription.Equals("expectation failed", StringComparison.CurrentCultureIgnoreCase)) && Response.StatusDescription.EqualsIgnoreCase("expectation failed"))
{ {
//read next line after expectation failed response //read next line after expectation failed response
Response.ExpectationFailed = true; Response.ExpectationFailed = true;
......
...@@ -33,6 +33,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -33,6 +33,7 @@ namespace Titanium.Web.Proxy.Http
public const string Host = "host"; public const string Host = "host";
public const string ProxyAuthorization = "Proxy-Authorization"; public const string ProxyAuthorization = "Proxy-Authorization";
public const string ProxyAuthorizationBasic = "basic";
public const string ProxyConnection = "Proxy-Connection"; public const string ProxyConnection = "Proxy-Connection";
public const string ProxyConnectionClose = "close"; public const string ProxyConnectionClose = "close";
......
...@@ -58,7 +58,33 @@ namespace Titanium.Web.Proxy.Http ...@@ -58,7 +58,33 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Has request body? /// Has request body?
/// </summary> /// </summary>
public bool HasBody => Method == "POST" || Method == "PUT" || Method == "PATCH"; public bool HasBody
{
get
{
long contentLength = ContentLength;
//If content length is set to 0 the request has no body
if (contentLength == 0)
{
return false;
}
//Has body only if request is chunked or content length >0
if (IsChunked || contentLength > 0)
{
return true;
}
//has body if POST and when version is http/1.0
if (Method == "POST" && HttpVersion == HttpHeader.Version10)
{
return true;
}
return false;
}
}
/// <summary> /// <summary>
/// Http hostname header value if exists /// Http hostname header value if exists
...@@ -248,7 +274,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -248,7 +274,7 @@ namespace Titanium.Web.Proxy.Http
return false; return false;
} }
return headerValue.Equals(KnownHeaders.UpgradeWebsocket, StringComparison.CurrentCultureIgnoreCase); return headerValue.EqualsIgnoreCase(KnownHeaders.UpgradeWebsocket);
} }
} }
......
...@@ -98,7 +98,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -98,7 +98,7 @@ namespace Titanium.Web.Proxy.Http
if (headerValue != null) if (headerValue != null)
{ {
if (headerValue.ContainsIgnoreCase(KnownHeaders.ConnectionClose)) if (headerValue.EqualsIgnoreCase(KnownHeaders.ConnectionClose))
{ {
return false; return false;
} }
......
...@@ -86,9 +86,12 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -86,9 +86,12 @@ namespace Titanium.Web.Proxy.Network.Tcp
using (var reader = new CustomBinaryReader(stream, server.BufferSize)) using (var reader = new CustomBinaryReader(stream, server.BufferSize))
{ {
string result = await reader.ReadLineAsync(); string httpStatus = await reader.ReadLineAsync();
if (!new[] { "200 OK", "connection established" }.Any(s => result.ContainsIgnoreCase(s))) Response.ParseResponseLine(httpStatus, out var version, out int statusCode, out string statusDescription);
if (!statusDescription.EqualsIgnoreCase("200 OK")
&& !statusDescription.EqualsIgnoreCase("connection established"))
{ {
throw new Exception("Upstream proxy failed to create a secure tunnel"); throw new Exception("Upstream proxy failed to create a secure tunnel");
} }
...@@ -99,7 +102,6 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -99,7 +102,6 @@ namespace Titanium.Web.Proxy.Network.Tcp
if (isHttps) if (isHttps)
{ {
var sslStream = new SslStream(stream, false, server.ValidateServerCertificate, server.SelectClientCertificate); var sslStream = new SslStream(stream, false, server.ValidateServerCertificate, server.SelectClientCertificate);
stream = new CustomBufferedStream(sslStream, server.BufferSize); stream = new CustomBufferedStream(sslStream, server.BufferSize);
......
...@@ -5,6 +5,7 @@ using System.Text; ...@@ -5,6 +5,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Exceptions; using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
...@@ -33,7 +34,7 @@ namespace Titanium.Web.Proxy ...@@ -33,7 +34,7 @@ namespace Titanium.Web.Proxy
} }
var headerValueParts = header.Value.Split(ProxyConstants.SpaceSplit); var headerValueParts = header.Value.Split(ProxyConstants.SpaceSplit);
if (headerValueParts.Length != 2 || !headerValueParts[0].Equals("basic", StringComparison.CurrentCultureIgnoreCase)) if (headerValueParts.Length != 2 || !headerValueParts[0].EqualsIgnoreCase(KnownHeaders.ProxyAuthorizationBasic))
{ {
//Return not authorized //Return not authorized
session.WebSession.Response = await SendAuthentication407Response(clientStreamWriter, "Proxy Authentication Invalid"); session.WebSession.Response = await SendAuthentication407Response(clientStreamWriter, "Proxy Authentication Invalid");
......
...@@ -196,7 +196,7 @@ namespace Titanium.Web.Proxy ...@@ -196,7 +196,7 @@ namespace Titanium.Web.Proxy
((ConnectResponse)connectArgs.WebSession.Response).ServerHelloInfo = serverHelloInfo; ((ConnectResponse)connectArgs.WebSession.Response).ServerHelloInfo = serverHelloInfo;
} }
await TcpHelper.SendRawApm(clientStream, connection.Stream, BufferSize, await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize,
(buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); },
(buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); }, (buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); },
ExceptionFunc); ExceptionFunc);
...@@ -475,7 +475,7 @@ namespace Titanium.Web.Proxy ...@@ -475,7 +475,7 @@ namespace Titanium.Web.Proxy
await BeforeResponse.InvokeAsync(this, args, ExceptionFunc); await BeforeResponse.InvokeAsync(this, args, ExceptionFunc);
} }
await TcpHelper.SendRawApm(clientStream, connection.Stream, BufferSize, await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize,
(buffer, offset, count) => { args.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { args.OnDataSent(buffer, offset, count); },
(buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); }, (buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); },
ExceptionFunc); ExceptionFunc);
......
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