* Add HTTP proxy support in forward proxy Signed-off-by: noisyfox <timemanager.rick@gmail.com> * Typo * Throw exception if forward proxy not supported.tags/3.3.2
@@ -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)), | |||
@@ -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" /> | |||