У меня есть одна внешняя программа, которая не поддерживает прокси для доступа в Интернет, но мне нужен прокси.
В качестве решения я написал одно простое приложение Delphi, используя Indy 10.6.0.5040 и его компонент TIdMappedPortTCP. Как это работает просто, внешнее приложение подключается к IdMappedPortTCP локально, а IdMappedPortTCP подключается к реальному серверу, используя мои настройки прокси.
Чтобы выполнить настройку прокси, я обработал событие OnConnect для IdMappedPortTCP, как показано ниже:
procedure TForm1.IdMappedPortTCP1Connect(AContext: TIdContext);
var
io: TIdIOHandlerStack;
proxy: TIdConnectThroughHttpProxy;
begin
if Assigned(TIdMappedPortContext(AContext).OutboundClient) then
begin
io := TIdIOHandlerStack.Create(TIdMappedPortContext(AContext).OutboundClient);
proxy := TIdConnectThroughHttpProxy.Create(io);
proxy.Enabled := False;
proxy.Host := FSettings.ProxyAddress;
proxy.Port := FSettings.ProxyPort;
proxy.Username := FSettings.ProxyUserName;
proxy.Password := FSettings.ProxyPassword;
If (proxy.Username <> '') or (proxy.Password <> '') then proxy.AuthorizationRequired(True);
proxy.Enabled := True;
io.DefaultPort := FSettings.DestinationPort[0];
io.Port := FSettings.DestinationPort[0];
io.Destination := FSettings.DestinationHostAddress[0];
io.Host := FSettings.DestinationHostAddress[0];
io.TransparentProxy := proxy;
io.OnStatus := StackStatus;
TIdMappedPortContext(AContext).OutboundClient.IOHandler := io;
end;
Log(Format('Listener connected at %s:%d', [TIdMappedPortContext(AContext).Server.MappedHost, TIdMappedPortContext(AContext).Server.MappedPort]));
end;
{ TIdConnectThroughHttpProxyHelper }
procedure TIdConnectThroughHttpProxyHelper.AuthorizationRequired(const val: boolean);
begin
Self.FAuthorizationRequired := val;
end;
procedure TForm1.Log(const s: string);
begin
Memo1.Lines.Add(Format('(%s) %s', [FormatDateTime('hh:nn:ss:zzz', Now), s]));
end;
procedure TForm1.IdMappedPortTCP1Disconnect(AContext: TIdContext);
begin
// Log(Format('Listener disconnected at %s:%d', [TIdMappedPortContext(AContext).Server.MappedHost, TIdMappedPortContext(AContext).Server.MappedPort]));
end;
procedure TForm1.IdMappedPortTCP1Exception(AContext: TIdContext;
AException: Exception);
begin
Log(Format('Exception: %s (%s:%d)', [AException.Message,TIdMappedPortContext(AContext).Server.MappedHost, TIdMappedPortContext(AContext).Server.MappedPort]));
end;
procedure TForm1.IdMappedPortTCP1ListenException(AThread: TIdListenerThread;
AException: Exception);
begin
Log(Format('Listener Exception: %s', [AException.Message]));
end;
procedure TForm1.IdMappedPortTCP1OutboundConnect(AContext: TIdContext);
begin
Log('MappedPort Destination connected.');
end;
procedure TForm1.IdMappedPortTCP1OutboundDisconnect(AContext: TIdContext);
begin
Log('MappedPort Destination disconnected.');
end;
procedure TForm1.StackStatus(ASender: TObject;
const AStatus: TIdStatus; const AStatusText: string);
begin
Log(Format('Stack Status: %s', [AStatusText]));
end;
У меня много активных подключений и все работают без нареканий. Моя проблема в том, что если я попытаюсь деактивировать IdMappedPortTCP, используя "IdMappedPortTCP.Active:= false;" пока есть активные трафики, соединения, он там висит и мне пришлось завершать приложение delphi с помощью диспетчера задач.
Есть ли что-нибудь, что мне нужно сделать вручную, прежде чем установить для Active значение false?
Спасибо.
AuthorizationRequired()
вручную, пустьTIdConnectThroughHttpProxy
сделает это. И вам не нужно устанавливать какие-либо свойстваTIdIOHandlerStack
, кромеTransparentProxy
иOnStatus
, пустьTIdTCPClient
справится с этим. - person Remy Lebeau   schedule 02.02.2014FAuthorizationRequired
— это внутренняя переменная, не связывайтесь с ней. По умолчанию он всегда равен false, а затем временно устанавливается в true, еслиIOHandler
необходимо закрыть и снова открыть, поскольку прокси-сервер отправил ответ407
с заголовком ответаConnection: close
илиProxy-Connection: close
. Повторное открытиеIOHandler
приводит к повторному вызовуMakeConnection()
, когда он уже запущен, поэтомуFAuthorizationRequired
используется для обнаружения второго подключения, поэтому к новому запросу добавляется заголовок запросаProxy-Authorization
. - person Remy Lebeau   schedule 03.02.2014TIdConnectThroughHttpProxy
не отправляет авторизацию, если только прокси явно не запрашивает ее.TIdHTTP
работает так же. - person Remy Lebeau   schedule 03.02.2014OnConnect
иOnDisconnect
запускаются в контексте рабочего потока, а не основного потока пользовательского интерфейса. Таким образом, вы должны синхронизироваться с основным потоком, например, с методамиTThread.Synchronize()
илиTThread.Queue()
или классами IndyTIdSync
илиTIdNotify
, чтобы безопасно получать доступ к компонентам пользовательского интерфейса. Если основной поток деактивирует сервер, асинхронный подход (TThread.Queue()
илиTIdNotify
) предпочтительнее синхронного (TThread.Synchronize()
илиTIdSync
), чтобы избежать взаимоблокировки. - person Remy Lebeau   schedule 03.02.2014