using Org.Mentalis.Network.ProxySocket;
using System;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class SocksHttpWebRequest : WebRequest
{
	private Encoding _correctEncoding;

	private readonly Uri _requestUri;

	private WebHeaderCollection _requestHeaders;

	private string _method;

	private SocksHttpWebResponse _response;

	private string _requestMessage;

	private byte[] _requestContentBuffer;

	private static readonly StringCollection validHttpVerbs = new StringCollection
	{
		"GET",
		"HEAD",
		"POST",
		"PUT",
		"DELETE",
		"TRACE",
		"OPTIONS"
	};

	public override Uri RequestUri
	{
		get
		{
			return this._requestUri;
		}
	}

	public override IWebProxy Proxy
	{
		get;
		set;
	}

	public override WebHeaderCollection Headers
	{
		get
		{
			if (this._requestHeaders == null)
			{
				this._requestHeaders = new WebHeaderCollection();
			}
			return this._requestHeaders;
		}
		set
		{
			if (this.RequestSubmitted)
			{
				throw new InvalidOperationException("This operation cannot be performed after the request has been submitted.");
			}
			this._requestHeaders = value;
		}
	}

	public bool RequestSubmitted
	{
		get;
		private set;
	}

	public override string Method
	{
		get
		{
			return this._method ?? "GET";
		}
		set
		{
			if (SocksHttpWebRequest.validHttpVerbs.Contains(value))
			{
				this._method = value;
				return;
			}
			throw new ArgumentOutOfRangeException("value", string.Format("'{0}' is not a known HTTP verb.", value));
		}
	}

	public override long ContentLength
	{
		get;
		set;
	}

	public override string ContentType
	{
		get;
		set;
	}

	public Encoding CorrectEncoding
	{
		get
		{
			return this._correctEncoding;
		}
	}

	public string RequestMessage
	{
		get
		{
			if (string.IsNullOrEmpty(this._requestMessage))
			{
				this._requestMessage = this.BuildHttpRequestMessage();
			}
			return this._requestMessage;
		}
	}

	private SocksHttpWebRequest(Uri requestUri)
	{
		this._requestUri = requestUri;
		this._correctEncoding = Encoding.Default;
	}

	public override WebResponse GetResponse()
	{
		if (this.Proxy == null)
		{
			throw new InvalidOperationException("Proxy property cannot be null.");
		}
		if (string.IsNullOrEmpty(this.Method))
		{
			throw new InvalidOperationException("Method has not been set.");
		}
		WebResponse response;
		if (this.RequestSubmitted)
		{
			response = this._response;
		}
		else
		{
			this._response = this.InternalGetResponse();
			this.RequestSubmitted = true;
			response = this._response;
		}
		return response;
	}

	public override Stream GetRequestStream()
	{
		if (this.RequestSubmitted)
		{
			throw new InvalidOperationException("This operation cannot be performed after the request has been submitted.");
		}
		if (this._requestContentBuffer == null)
		{
			this._requestContentBuffer = new byte[this.ContentLength];
		}
		else if (this.ContentLength == 0L)
		{
			this._requestContentBuffer = new byte[2147483647];
		}
		else if ((long)this._requestContentBuffer.Length != this.ContentLength)
		{
			Array.Resize<byte>(ref this._requestContentBuffer, (int)this.ContentLength);
		}
		return new MemoryStream(this._requestContentBuffer);
	}

	public new static WebRequest Create(string requestUri)
	{
		return new SocksHttpWebRequest(new Uri(requestUri));
	}

	public new static WebRequest Create(Uri requestUri)
	{
		return new SocksHttpWebRequest(requestUri);
	}

	private string BuildHttpRequestMessage()
	{
		if (this.RequestSubmitted)
		{
			throw new InvalidOperationException("This operation cannot be performed after the request has been submitted.");
		}
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.AppendFormat("{0} {1} HTTP/1.0\r\nHost: {2}\r\n", this.Method, this.RequestUri.PathAndQuery, this.RequestUri.Host);
		foreach (object current in this.Headers.Keys)
		{
			stringBuilder.AppendFormat("{0}: {1}\r\n", current, this.Headers[current.ToString()]);
		}
		if (!string.IsNullOrEmpty(this.ContentType))
		{
			stringBuilder.AppendFormat("Content-Type: {0}\r\n", this.ContentType);
		}
		if (this.ContentLength > 0L)
		{
			stringBuilder.AppendFormat("Content-Length: {0}\r\n", this.ContentLength);
		}
		stringBuilder.Append("\r\n");
		if (this._requestContentBuffer != null && this._requestContentBuffer.Length > 0)
		{
			using (MemoryStream memoryStream = new MemoryStream(this._requestContentBuffer, false))
			{
				using (StreamReader streamReader = new StreamReader(memoryStream))
				{
					stringBuilder.Append(streamReader.ReadToEnd());
				}
			}
		}
		return stringBuilder.ToString();
	}

	private SocksHttpWebResponse InternalGetResponse()
	{
		StringBuilder stringBuilder = new StringBuilder();
		using (ProxySocket proxySocket = new ProxySocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
		{
			Uri proxy = this.Proxy.GetProxy(this.RequestUri);
			IPAddress proxyIpAddress = SocksHttpWebRequest.GetProxyIpAddress(proxy);
			proxySocket.ProxyEndPoint = new IPEndPoint(proxyIpAddress, proxy.Port);
			proxySocket.ProxyType = ProxyTypes.Socks5;
			proxySocket.Connect(this.RequestUri.Host, 80);
			proxySocket.Send(this._correctEncoding.GetBytes(this.RequestMessage));
			byte[] array = new byte[1024];
			for (int i = proxySocket.Receive(array); i > 0; i = proxySocket.Receive(array))
			{
				string @string = this._correctEncoding.GetString(array, 0, i);
				string encodingFromChunk = EncodingHelper.GetEncodingFromChunk(@string);
				if (!string.IsNullOrEmpty(encodingFromChunk))
				{
					try
					{
						this._correctEncoding = Encoding.GetEncoding(encodingFromChunk);
					}
					catch
					{
					}
				}
				stringBuilder.Append(@string);
			}
		}
		return new SocksHttpWebResponse(stringBuilder.ToString(), this._correctEncoding);
	}

	private static IPAddress GetProxyIpAddress(Uri proxyUri)
	{
		IPAddress iPAddress;
		IPAddress result;
		if (!IPAddress.TryParse(proxyUri.Host, out iPAddress))
		{
			try
			{
				result = Dns.GetHostEntry(proxyUri.Host).AddressList[0];
				return result;
			}
			catch (Exception innerException)
			{
				throw new InvalidOperationException(string.Format("Unable to resolve proxy hostname '{0}' to a valid IP address.", proxyUri.Host), innerException);
			}
		}
		result = iPAddress;
		return result;
	}
}
