Add HTTP proxy support in forward proxy (#745)
* Add HTTP proxy support in forward proxy Signed-off-by: noisyfox <timemanager.rick@gmail.com> * Typo * Throw exception if forward proxy not supported.
This commit is contained in:
@@ -420,7 +420,17 @@ namespace Shadowsocks.Controller
|
||||
EndPoint proxyEP;
|
||||
if (_config.proxy.useProxy)
|
||||
{
|
||||
remote = new Socks5Proxy();
|
||||
switch (_config.proxy.proxyType)
|
||||
{
|
||||
case ProxyConfig.PROXY_SOCKS5:
|
||||
remote = new Socks5Proxy();
|
||||
break;
|
||||
case ProxyConfig.PROXY_HTTP:
|
||||
remote = new HttpProxy();
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException("Unknown forward proxy.");
|
||||
}
|
||||
proxyEP = SocketUtil.GetEndPoint(_config.proxy.proxyServer, _config.proxy.proxyPort);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -221,9 +221,10 @@ namespace Shadowsocks.Controller
|
||||
SaveConfig(_config);
|
||||
}
|
||||
|
||||
public void EnableProxy(string proxy, int port)
|
||||
public void EnableProxy(int type, string proxy, int port)
|
||||
{
|
||||
_config.proxy.useProxy = true;
|
||||
_config.proxy.proxyType = type;
|
||||
_config.proxy.proxyServer = proxy;
|
||||
_config.proxy.proxyPort = port;
|
||||
SaveConfig(_config);
|
||||
|
||||
@@ -12,7 +12,7 @@ Servers=服务器
|
||||
Edit Servers...=编辑服务器...
|
||||
Statistics Config...=统计配置...
|
||||
Start on Boot=开机启动
|
||||
SOCKS5 Proxy...=SOCKS5代理设置...
|
||||
Forward Proxy...=正向代理设置...
|
||||
Allow Clients from LAN=允许来自局域网的连接
|
||||
Local PAC=使用本地 PAC
|
||||
Online PAC=使用在线 PAC
|
||||
@@ -58,6 +58,7 @@ Move D&own=下移(&O)
|
||||
|
||||
Edit Proxy=代理设置
|
||||
Use Proxy=使用代理
|
||||
Proxy Type=代理类型
|
||||
Proxy Addr=代理地址
|
||||
Proxy Port=代理端口
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Servers=伺服器
|
||||
Edit Servers...=編輯伺服器...
|
||||
Statistics Config...=統計配置...
|
||||
Start on Boot=開機啟動
|
||||
SOCKS5 Proxy...=SOCKS5代理設置...
|
||||
Forward Proxy...=正向代理設置...
|
||||
Allow Clients from LAN=允許來自區域網路的連接
|
||||
Local PAC=使用本地 PAC
|
||||
Online PAC=使用在線 PAC
|
||||
@@ -58,6 +58,7 @@ Move D&own=下移(&O)
|
||||
|
||||
Edit Proxy=代理設置
|
||||
Use Proxy=使用代理
|
||||
Proxy Type=代理類別
|
||||
Proxy Addr=代理位址
|
||||
Proxy Port=代理連接埠
|
||||
|
||||
|
||||
@@ -63,6 +63,11 @@ namespace Shadowsocks.Model
|
||||
config.proxy = new ProxyConfig();
|
||||
if (config.hotkey == null)
|
||||
config.hotkey = new HotkeyConfig();
|
||||
|
||||
if (config.proxy.proxyType < ProxyConfig.PROXY_SOCKS5 || config.proxy.proxyType > ProxyConfig.PROXY_HTTP)
|
||||
{
|
||||
config.proxy.proxyType = ProxyConfig.PROXY_SOCKS5;
|
||||
}
|
||||
return config;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
using Shadowsocks.View;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using System;
|
||||
|
||||
namespace Shadowsocks.Model
|
||||
{
|
||||
[Serializable]
|
||||
public class ProxyConfig
|
||||
{
|
||||
public const int PROXY_SOCKS5 = 0;
|
||||
public const int PROXY_HTTP = 1;
|
||||
|
||||
public bool useProxy;
|
||||
public int proxyType;
|
||||
public string proxyServer;
|
||||
public int proxyPort;
|
||||
|
||||
public ProxyConfig()
|
||||
{
|
||||
useProxy = false;
|
||||
proxyType = PROXY_SOCKS5;
|
||||
proxyServer = "";
|
||||
proxyPort = 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using Shadowsocks.Controller;
|
||||
using Shadowsocks.Util.Sockets;
|
||||
|
||||
namespace Shadowsocks.Proxy
|
||||
{
|
||||
public class HttpProxy : IProxy
|
||||
{
|
||||
private class FakeAsyncResult : IAsyncResult
|
||||
{
|
||||
public readonly HttpState innerState;
|
||||
|
||||
private readonly IAsyncResult r;
|
||||
|
||||
public FakeAsyncResult(IAsyncResult orig, HttpState state)
|
||||
{
|
||||
r = orig;
|
||||
innerState = state;
|
||||
}
|
||||
|
||||
public bool IsCompleted => r.IsCompleted;
|
||||
public WaitHandle AsyncWaitHandle => r.AsyncWaitHandle;
|
||||
public object AsyncState => innerState.AsyncState;
|
||||
public bool CompletedSynchronously => r.CompletedSynchronously;
|
||||
}
|
||||
|
||||
private class HttpState
|
||||
{
|
||||
|
||||
public AsyncCallback Callback { get; set; }
|
||||
|
||||
public object AsyncState { get; set; }
|
||||
|
||||
public int BytesToRead;
|
||||
|
||||
public Exception ex { get; set; }
|
||||
}
|
||||
|
||||
public EndPoint LocalEndPoint => _remote.LocalEndPoint;
|
||||
public EndPoint ProxyEndPoint { get; private set; }
|
||||
public EndPoint DestEndPoint { get; private set; }
|
||||
|
||||
|
||||
private readonly WrappedSocket _remote = new WrappedSocket();
|
||||
|
||||
|
||||
public void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state)
|
||||
{
|
||||
ProxyEndPoint = remoteEP;
|
||||
|
||||
_remote.BeginConnect(remoteEP, callback, state);
|
||||
}
|
||||
|
||||
public void EndConnectProxy(IAsyncResult asyncResult)
|
||||
{
|
||||
_remote.EndConnect(asyncResult);
|
||||
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
|
||||
}
|
||||
|
||||
private const string HTTP_CRLF = "\r\n";
|
||||
private const string HTTP_CONNECT_TEMPLATE =
|
||||
"CONNECT {0} HTTP/1.1" + HTTP_CRLF +
|
||||
"Host: {0}" + HTTP_CRLF +
|
||||
"Proxy-Connection: keep-alive" + HTTP_CRLF +
|
||||
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36" + HTTP_CRLF +
|
||||
"" + HTTP_CRLF; // End with an empty line
|
||||
|
||||
public void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state)
|
||||
{
|
||||
DestEndPoint = destEndPoint;
|
||||
string request = string.Format(HTTP_CONNECT_TEMPLATE, destEndPoint);
|
||||
|
||||
var b = Encoding.UTF8.GetBytes(request);
|
||||
|
||||
var st = new HttpState();
|
||||
st.Callback = callback;
|
||||
st.AsyncState = state;
|
||||
|
||||
_remote.BeginSend(b, 0, b.Length, 0, HttpRequestSendCallback, st);
|
||||
}
|
||||
|
||||
public void EndConnectDest(IAsyncResult asyncResult)
|
||||
{
|
||||
var state = ((FakeAsyncResult)asyncResult).innerState;
|
||||
|
||||
if (state.ex != null)
|
||||
{
|
||||
throw state.ex;
|
||||
}
|
||||
}
|
||||
|
||||
public void BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback,
|
||||
object state)
|
||||
{
|
||||
_remote.BeginSend(buffer, offset, size, socketFlags, callback, state);
|
||||
}
|
||||
|
||||
public int EndSend(IAsyncResult asyncResult)
|
||||
{
|
||||
return _remote.EndSend(asyncResult);
|
||||
}
|
||||
|
||||
public void BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback,
|
||||
object state)
|
||||
{
|
||||
_remote.BeginReceive(buffer, offset, size, socketFlags, callback, state);
|
||||
}
|
||||
|
||||
public int EndReceive(IAsyncResult asyncResult)
|
||||
{
|
||||
return _remote.EndReceive(asyncResult);
|
||||
}
|
||||
|
||||
public void Shutdown(SocketShutdown how)
|
||||
{
|
||||
_remote.Shutdown(how);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
_remote.Dispose();
|
||||
}
|
||||
|
||||
private void HttpRequestSendCallback(IAsyncResult ar)
|
||||
{
|
||||
var state = (HttpState) ar.AsyncState;
|
||||
try
|
||||
{
|
||||
_remote.EndSend(ar);
|
||||
|
||||
// start line read
|
||||
new LineReader(_remote, OnLineRead, OnException, OnFinish, Encoding.UTF8, HTTP_CRLF, 1024, new FakeAsyncResult(ar, state));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
state.ex = ex;
|
||||
state.Callback?.Invoke(new FakeAsyncResult(ar, state));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFinish(byte[] lastBytes, int index, int length, object state)
|
||||
{
|
||||
// TODO: save last bytes
|
||||
var st = (FakeAsyncResult)state;
|
||||
|
||||
if (!_established)
|
||||
{
|
||||
st.innerState.ex = new Exception(I18N.GetString("Proxy request failed"));
|
||||
}
|
||||
st.innerState.Callback?.Invoke(st);
|
||||
}
|
||||
|
||||
private void OnException(Exception ex, object state)
|
||||
{
|
||||
var st = (FakeAsyncResult) state;
|
||||
|
||||
st.innerState.ex = ex;
|
||||
st.innerState.Callback?.Invoke(st);
|
||||
}
|
||||
|
||||
private static readonly Regex HttpRespondHeaderRegex = new Regex(@"^(HTTP/1\.\d) (\d{3}) (.+)$");
|
||||
private int _respondLineCount = 0;
|
||||
private bool _established = false;
|
||||
|
||||
private bool OnLineRead(string line, object state)
|
||||
{
|
||||
Logging.Debug(line);
|
||||
|
||||
if (_respondLineCount == 0)
|
||||
{
|
||||
var m = HttpRespondHeaderRegex.Match(line);
|
||||
if (m.Success)
|
||||
{
|
||||
var resultCode = m.Groups[2].Value;
|
||||
if ("200" != resultCode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
_established = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (line.IsNullOrEmpty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_respondLineCount++;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ namespace Shadowsocks.Proxy
|
||||
public Exception ex { get; set; }
|
||||
}
|
||||
|
||||
private WrappedSocket _remote = new WrappedSocket();
|
||||
private readonly WrappedSocket _remote = new WrappedSocket();
|
||||
|
||||
private const int Socks5PktMaxSize = 4 + 16 + 2;
|
||||
private readonly byte[] _receiveBuffer = new byte[Socks5PktMaxSize];
|
||||
@@ -124,7 +124,7 @@ namespace Shadowsocks.Proxy
|
||||
st.Callback = callback;
|
||||
st.AsyncState = state;
|
||||
|
||||
_remote?.BeginSend(request, 0, request.Length, 0, Socks5RequestSendCallback, st);
|
||||
_remote.BeginSend(request, 0, request.Length, 0, Socks5RequestSendCallback, st);
|
||||
}
|
||||
|
||||
public void EndConnectDest(IAsyncResult asyncResult)
|
||||
@@ -140,7 +140,7 @@ namespace Shadowsocks.Proxy
|
||||
public void BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback,
|
||||
object state)
|
||||
{
|
||||
_remote?.BeginSend(buffer, offset, size, socketFlags, callback, state);
|
||||
_remote.BeginSend(buffer, offset, size, socketFlags, callback, state);
|
||||
}
|
||||
|
||||
public int EndSend(IAsyncResult asyncResult)
|
||||
@@ -151,7 +151,7 @@ namespace Shadowsocks.Proxy
|
||||
public void BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback,
|
||||
object state)
|
||||
{
|
||||
_remote?.BeginReceive(buffer, offset, size, socketFlags, callback, state);
|
||||
_remote.BeginReceive(buffer, offset, size, socketFlags, callback, state);
|
||||
}
|
||||
|
||||
public int EndReceive(IAsyncResult asyncResult)
|
||||
@@ -161,12 +161,12 @@ namespace Shadowsocks.Proxy
|
||||
|
||||
public void Shutdown(SocketShutdown how)
|
||||
{
|
||||
_remote?.Shutdown(how);
|
||||
_remote.Shutdown(how);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
_remote?.Dispose();
|
||||
_remote.Dispose();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Shadowsocks.Util.Sockets
|
||||
{
|
||||
public class LineReader
|
||||
{
|
||||
private readonly WrappedSocket _socket;
|
||||
private readonly Func<string, object, bool> _onLineRead;
|
||||
private readonly Action<Exception, object> _onException;
|
||||
private readonly Action<byte[], int, int, object> _onFinish;
|
||||
private readonly Encoding _encoding;
|
||||
// private readonly string _delimiter;
|
||||
private readonly byte[] _delimiterBytes;
|
||||
private readonly int[] _delimiterSearchCharTable;
|
||||
private readonly int[] _delimiterSearchOffsetTable;
|
||||
private readonly object _state;
|
||||
|
||||
private readonly byte[] _lineBuffer;
|
||||
|
||||
private int _bufferIndex;
|
||||
|
||||
public LineReader(WrappedSocket socket, Func<string, object, bool> onLineRead, Action<Exception, object> onException,
|
||||
Action<byte[], int, int, object> onFinish, Encoding encoding, string delimiter, int maxLineBytes, object state)
|
||||
{
|
||||
if (socket == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(socket));
|
||||
}
|
||||
if (onLineRead == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(onLineRead));
|
||||
}
|
||||
if (encoding == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(encoding));
|
||||
}
|
||||
if (delimiter == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(delimiter));
|
||||
}
|
||||
|
||||
_socket = socket;
|
||||
_onLineRead = onLineRead;
|
||||
_onException = onException;
|
||||
_onFinish = onFinish;
|
||||
_encoding = encoding;
|
||||
// _delimiter = delimiter;
|
||||
_state = state;
|
||||
|
||||
// decode delimiter
|
||||
_delimiterBytes = encoding.GetBytes(delimiter);
|
||||
|
||||
if (_delimiterBytes.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("Too short!", nameof(delimiter));
|
||||
}
|
||||
|
||||
if (maxLineBytes < _delimiterBytes.Length)
|
||||
{
|
||||
throw new ArgumentException("Too small!", nameof(maxLineBytes));
|
||||
}
|
||||
|
||||
_delimiterSearchCharTable = MakeCharTable(_delimiterBytes);
|
||||
_delimiterSearchOffsetTable = MakeOffsetTable(_delimiterBytes);
|
||||
|
||||
_lineBuffer = new byte[maxLineBytes];
|
||||
|
||||
// start reading
|
||||
socket.BeginReceive(_lineBuffer, 0, maxLineBytes, 0, ReceiveCallback, 0);
|
||||
}
|
||||
|
||||
private void ReceiveCallback(IAsyncResult ar)
|
||||
{
|
||||
int length = (int)ar.AsyncState;
|
||||
try
|
||||
{
|
||||
var bytesRead = _socket.EndReceive(ar);
|
||||
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
OnFinish(length);
|
||||
return;
|
||||
}
|
||||
|
||||
length += bytesRead;
|
||||
|
||||
int i;
|
||||
while ((i = IndexOf(_lineBuffer, _bufferIndex, length, _delimiterBytes, _delimiterSearchOffsetTable,
|
||||
_delimiterSearchCharTable)) != -1)
|
||||
{
|
||||
var decodeLen = i - _bufferIndex;
|
||||
string line = _encoding.GetString(_lineBuffer, _bufferIndex, decodeLen);
|
||||
|
||||
_bufferIndex = i + _delimiterBytes.Length;
|
||||
length -= decodeLen;
|
||||
length -= _delimiterBytes.Length;
|
||||
|
||||
var stop = _onLineRead(line, _state);
|
||||
if (stop)
|
||||
{
|
||||
OnFinish(length);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (length == _lineBuffer.Length)
|
||||
{
|
||||
OnException(new IndexOutOfRangeException("LineBuffer full! Try increace maxLineBytes!"));
|
||||
OnFinish(length);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (_bufferIndex > 0)
|
||||
{
|
||||
Buffer.BlockCopy(_lineBuffer, _bufferIndex, _lineBuffer, 0, length);
|
||||
_bufferIndex = 0;
|
||||
}
|
||||
|
||||
_socket.BeginReceive(_lineBuffer, length, _lineBuffer.Length - length, 0, ReceiveCallback, length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnException(ex);
|
||||
OnFinish(length);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnException(Exception ex)
|
||||
{
|
||||
_onException?.Invoke(ex, _state);
|
||||
}
|
||||
|
||||
private void OnFinish(int length)
|
||||
{
|
||||
_onFinish?.Invoke(_lineBuffer, _bufferIndex, length, _state);
|
||||
}
|
||||
|
||||
#region Boyer-Moore string search
|
||||
|
||||
public static int IndexOf(byte[] haystack, int index, int length, byte[] needle, int[] offsetTable, int[] charTable)
|
||||
{
|
||||
var end = index + length;
|
||||
for (int i = needle.Length - 1 + index, j; i < end;)
|
||||
{
|
||||
for (j = needle.Length - 1; needle[j] == haystack[i]; --i, --j)
|
||||
{
|
||||
if (j == 0)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// i += needle.length - j; // For naive method
|
||||
i += Math.Max(offsetTable[needle.Length - 1 - j], charTable[haystack[i]]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the jump table based on the mismatched character information.
|
||||
*/
|
||||
private static int[] MakeCharTable(byte[] needle)
|
||||
{
|
||||
const int ALPHABET_SIZE = 256;
|
||||
int[] table = new int[ALPHABET_SIZE];
|
||||
for (int i = 0; i < table.Length; ++i)
|
||||
{
|
||||
table[i] = needle.Length;
|
||||
}
|
||||
for (int i = 0; i < needle.Length - 1; ++i)
|
||||
{
|
||||
table[needle[i]] = needle.Length - 1 - i;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the jump table based on the scan offset which mismatch occurs.
|
||||
*/
|
||||
private static int[] MakeOffsetTable(byte[] needle)
|
||||
{
|
||||
int[] table = new int[needle.Length];
|
||||
int lastPrefixPosition = needle.Length;
|
||||
for (int i = needle.Length - 1; i >= 0; --i)
|
||||
{
|
||||
if (IsPrefix(needle, i + 1))
|
||||
{
|
||||
lastPrefixPosition = i + 1;
|
||||
}
|
||||
table[needle.Length - 1 - i] = lastPrefixPosition - i + needle.Length - 1;
|
||||
}
|
||||
for (int i = 0; i < needle.Length - 1; ++i)
|
||||
{
|
||||
int slen = SuffixLength(needle, i);
|
||||
table[slen] = needle.Length - 1 - i + slen;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is needle[p:end] a prefix of needle?
|
||||
*/
|
||||
private static bool IsPrefix(byte[] needle, int p)
|
||||
{
|
||||
for (int i = p, j = 0; i < needle.Length; ++i, ++j)
|
||||
{
|
||||
if (needle[i] != needle[j])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum length of the substring ends at p and is a suffix.
|
||||
*/
|
||||
private static int SuffixLength(byte[] needle, int p)
|
||||
{
|
||||
int len = 0;
|
||||
for (int i = p, j = needle.Length - 1;
|
||||
i >= 0 && needle[i] == needle[j]; --i, --j)
|
||||
{
|
||||
len += 1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -271,7 +271,7 @@ namespace Shadowsocks.View
|
||||
this.editGFWUserRuleItem = CreateMenuItem("Edit User Rule for GFWList...", new EventHandler(this.EditUserRuleFileForGFWListItem_Click)),
|
||||
this.editOnlinePACItem = CreateMenuItem("Edit Online PAC URL...", new EventHandler(this.UpdateOnlinePACURLItem_Click)),
|
||||
}),
|
||||
this.proxyItem = CreateMenuItem("SOCKS5 Proxy...", new EventHandler(this.proxyItem_Click)),
|
||||
this.proxyItem = CreateMenuItem("Forward Proxy...", new EventHandler(this.proxyItem_Click)),
|
||||
new MenuItem("-"),
|
||||
this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)),
|
||||
this.ShareOverLANItem = CreateMenuItem("Allow Clients from LAN", new EventHandler(this.ShareOverLANItem_Click)),
|
||||
|
||||
+58
-7
@@ -38,9 +38,13 @@
|
||||
this.ProxyServerTextBox = new System.Windows.Forms.TextBox();
|
||||
this.ProxyPortLable = new System.Windows.Forms.Label();
|
||||
this.ProxyPortTextBox = new System.Windows.Forms.TextBox();
|
||||
this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.ProxyTypeLabel = new System.Windows.Forms.Label();
|
||||
this.ProxyTypeComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.tableLayoutPanel3.SuspendLayout();
|
||||
this.tableLayoutPanel2.SuspendLayout();
|
||||
this.tableLayoutPanel4.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
@@ -49,16 +53,18 @@
|
||||
this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.tableLayoutPanel1.ColumnCount = 1;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel3, 0, 2);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel3, 0, 3);
|
||||
this.tableLayoutPanel1.Controls.Add(this.UseProxyCheckBox, 0, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 2);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel4, 0, 1);
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(15, 15);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 3;
|
||||
this.tableLayoutPanel1.RowCount = 4;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(395, 87);
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(395, 123);
|
||||
this.tableLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// tableLayoutPanel3
|
||||
@@ -72,7 +78,7 @@
|
||||
this.tableLayoutPanel3.Controls.Add(this.MyCancelButton, 1, 0);
|
||||
this.tableLayoutPanel3.Controls.Add(this.OKButton, 0, 0);
|
||||
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Right;
|
||||
this.tableLayoutPanel3.Location = new System.Drawing.Point(236, 58);
|
||||
this.tableLayoutPanel3.Location = new System.Drawing.Point(236, 94);
|
||||
this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3);
|
||||
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
|
||||
this.tableLayoutPanel3.RowCount = 1;
|
||||
@@ -129,10 +135,11 @@
|
||||
this.tableLayoutPanel2.Controls.Add(this.ProxyServerTextBox, 1, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.ProxyPortLable, 2, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.ProxyPortTextBox, 3, 0);
|
||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 25);
|
||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 61);
|
||||
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
this.tableLayoutPanel2.RowCount = 1;
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel2.Size = new System.Drawing.Size(389, 27);
|
||||
this.tableLayoutPanel2.TabIndex = 1;
|
||||
//
|
||||
@@ -174,6 +181,45 @@
|
||||
this.ProxyPortTextBox.TabIndex = 3;
|
||||
this.ProxyPortTextBox.WordWrap = false;
|
||||
//
|
||||
// tableLayoutPanel4
|
||||
//
|
||||
this.tableLayoutPanel4.AutoSize = true;
|
||||
this.tableLayoutPanel4.ColumnCount = 2;
|
||||
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel4.Controls.Add(this.ProxyTypeLabel, 0, 0);
|
||||
this.tableLayoutPanel4.Controls.Add(this.ProxyTypeComboBox, 1, 0);
|
||||
this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 25);
|
||||
this.tableLayoutPanel4.Name = "tableLayoutPanel4";
|
||||
this.tableLayoutPanel4.RowCount = 1;
|
||||
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel4.Size = new System.Drawing.Size(198, 30);
|
||||
this.tableLayoutPanel4.TabIndex = 10;
|
||||
//
|
||||
// ProxyTypeLabel
|
||||
//
|
||||
this.ProxyTypeLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.ProxyTypeLabel.AutoSize = true;
|
||||
this.ProxyTypeLabel.Location = new System.Drawing.Point(3, 9);
|
||||
this.ProxyTypeLabel.Name = "ProxyTypeLabel";
|
||||
this.ProxyTypeLabel.Size = new System.Drawing.Size(65, 12);
|
||||
this.ProxyTypeLabel.TabIndex = 1;
|
||||
this.ProxyTypeLabel.Text = "Proxy Type";
|
||||
//
|
||||
// ProxyTypeComboBox
|
||||
//
|
||||
this.ProxyTypeComboBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ProxyTypeComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.ProxyTypeComboBox.FormattingEnabled = true;
|
||||
this.ProxyTypeComboBox.Items.AddRange(new object[] {
|
||||
"SOCKS5",
|
||||
"HTTP"});
|
||||
this.ProxyTypeComboBox.Location = new System.Drawing.Point(74, 5);
|
||||
this.ProxyTypeComboBox.Margin = new System.Windows.Forms.Padding(3, 5, 3, 5);
|
||||
this.ProxyTypeComboBox.Name = "ProxyTypeComboBox";
|
||||
this.ProxyTypeComboBox.Size = new System.Drawing.Size(121, 20);
|
||||
this.ProxyTypeComboBox.TabIndex = 2;
|
||||
//
|
||||
// ProxyForm
|
||||
//
|
||||
this.AcceptButton = this.OKButton;
|
||||
@@ -182,7 +228,7 @@
|
||||
this.AutoSize = true;
|
||||
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.CancelButton = this.MyCancelButton;
|
||||
this.ClientSize = new System.Drawing.Size(441, 149);
|
||||
this.ClientSize = new System.Drawing.Size(441, 165);
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.MaximizeBox = false;
|
||||
@@ -197,6 +243,8 @@
|
||||
this.tableLayoutPanel3.ResumeLayout(false);
|
||||
this.tableLayoutPanel2.ResumeLayout(false);
|
||||
this.tableLayoutPanel2.PerformLayout();
|
||||
this.tableLayoutPanel4.ResumeLayout(false);
|
||||
this.tableLayoutPanel4.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
@@ -214,5 +262,8 @@
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
|
||||
private System.Windows.Forms.Button MyCancelButton;
|
||||
private System.Windows.Forms.Button OKButton;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4;
|
||||
private System.Windows.Forms.Label ProxyTypeLabel;
|
||||
private System.Windows.Forms.ComboBox ProxyTypeComboBox;
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ namespace Shadowsocks.View
|
||||
private void UpdateTexts()
|
||||
{
|
||||
UseProxyCheckBox.Text = I18N.GetString("Use Proxy");
|
||||
ProxyTypeLabel.Text = I18N.GetString("Proxy Type");
|
||||
ProxyAddrLabel.Text = I18N.GetString("Proxy Addr");
|
||||
ProxyPortLable.Text = I18N.GetString("Proxy Port");
|
||||
OKButton.Text = I18N.GetString("OK");
|
||||
@@ -50,6 +51,7 @@ namespace Shadowsocks.View
|
||||
UseProxyCheckBox.Checked = _modifiedConfiguration.useProxy;
|
||||
ProxyServerTextBox.Text = _modifiedConfiguration.proxyServer;
|
||||
ProxyPortTextBox.Text = _modifiedConfiguration.proxyPort.ToString();
|
||||
ProxyTypeComboBox.SelectedIndex = _modifiedConfiguration.proxyType;
|
||||
}
|
||||
|
||||
private void OKButton_Click(object sender, EventArgs e)
|
||||
@@ -58,12 +60,13 @@ namespace Shadowsocks.View
|
||||
{
|
||||
try
|
||||
{
|
||||
var type = ProxyTypeComboBox.SelectedIndex;
|
||||
var proxy = ProxyServerTextBox.Text;
|
||||
var port = int.Parse(ProxyPortTextBox.Text);
|
||||
Configuration.CheckServer(proxy);
|
||||
Configuration.CheckPort(port);
|
||||
|
||||
controller.EnableProxy(proxy, port);
|
||||
controller.EnableProxy(type, proxy, port);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
@@ -82,6 +85,7 @@ namespace Shadowsocks.View
|
||||
}
|
||||
|
||||
_modifiedConfiguration.useProxy = UseProxyCheckBox.Checked;
|
||||
_modifiedConfiguration.proxyType = ProxyTypeComboBox.SelectedIndex;
|
||||
_modifiedConfiguration.proxyServer = ProxyServerTextBox.Text;
|
||||
var tmpProxyPort = 0;
|
||||
int.TryParse(ProxyPortTextBox.Text, out tmpProxyPort);
|
||||
@@ -112,6 +116,7 @@ namespace Shadowsocks.View
|
||||
{
|
||||
ProxyServerTextBox.Enabled = true;
|
||||
ProxyPortTextBox.Enabled = true;
|
||||
ProxyTypeComboBox.Enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -119,6 +124,7 @@ namespace Shadowsocks.View
|
||||
ProxyPortTextBox.Clear();
|
||||
ProxyServerTextBox.Enabled = false;
|
||||
ProxyPortTextBox.Enabled = false;
|
||||
ProxyTypeComboBox.Enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +146,7 @@
|
||||
<Compile Include="Model\HotKeyConfig.cs" />
|
||||
<Compile Include="Model\ProxyConfig.cs" />
|
||||
<Compile Include="Proxy\DirectConnect.cs" />
|
||||
<Compile Include="Proxy\HttpProxy.cs" />
|
||||
<Compile Include="Proxy\IProxy.cs" />
|
||||
<Compile Include="Controller\Service\AvailabilityStatistics.cs" />
|
||||
<Compile Include="Controller\Strategy\HighAvailabilityStrategy.cs" />
|
||||
@@ -186,6 +187,7 @@
|
||||
<Compile Include="Util\Hotkeys.cs" />
|
||||
<Compile Include="Util\ProcessManagement\Job.cs" />
|
||||
<Compile Include="Util\ProcessManagement\ThreadUtil.cs" />
|
||||
<Compile Include="Util\Sockets\LineReader.cs" />
|
||||
<Compile Include="Util\Sockets\SocketUtil.cs" />
|
||||
<Compile Include="Util\Sockets\WrappedSocket.cs" />
|
||||
<Compile Include="Util\Util.cs" />
|
||||
|
||||
Reference in New Issue
Block a user