Oh, it is that bug :((
Sorry for not including in the debate sooner, but I lost contact with
GpHttpProxy years ago when I started to work on a custom version for one of
my customers. Now I had no idea which of the problems I fixed years ago this
was (yes, I was not using source control at the time :( ).
The trick was to destroy remote socket and recreate it if host or port
changed.
I think this are the two most important parts:
procedure TGpHttpProxy.ProcessHeader(Client: TGpHttpProxyClient);
var
ahost : string;
aport : string;
header : string;
returnContent: string;
resetSocket : boolean;
begin
resetSocket := false;
returnContent := '';
header := Client.Received;
if SameText(FirstEl(header,' ',-1),'CONNECT') then begin
// TCP Tunnel proxy request
HttpData(Client).ProxyType := ptTCPTunnel;
if not IPSec.IsAllowed(Client.PeerAddr) then
returnContent := Response.sTCPTunnelIPForbidden.Text
else if not (ptTCPTunnel in EnabledTypes) then
returnContent := Response.sTCPTunnelClosed.Text
else if not
ProcessTCPTunnelHeader(Client,header,ahost,aport,returnContent) then
returnContent := Response.sTCPTunnelBadRequest.Text;
end
else begin
// HTTP proxy request
HttpData(Client).ProxyType := ptHTTP;
if not IPSec.IsAllowed(Client.PeerAddr) then
returnContent := Response.sHTTPIPForbidden.Text
else if not (ptHTTP in EnabledTypes) then
returnContent := Response.sHTTPClosed.Text
else if not
ProcessHTTPHeader(Client,header,ahost,aport,returnContent,resetSocket) then
returnContent := Response.sHTTPBadRequest.Text;
end; //else SameText()
// Header parsed, create remote socket.
if returnContent = '' then begin
if resetSocket then begin
{$IFDEF LogHttpFlow}
LogFlow(Client, 'Destroyed connection to %s:%s due to host/port
change',
[Client.RemoteHost, Client.RemoteSocket.Port]);
{$ENDIF LogHttpFlow}
Client.DestroyRemoteSocket;
Client.NumRequests := 1;
end;
if not assigned(Client.RemoteSocket) then with Client do begin
{$IFDEF LogHttpFlow}
LogFlow(Client, 'Opening connection to %s:%s', [ahost, aport]);
{$ENDIF LogHttpFlow}
CreateRemoteSocket;
RemoteHost := ahost;
RemoteSocket.Port := aport;
RemoteSocket.LineMode := false;
HookRemoteEvents(RemoteSocket);
RemoteSocket.DnsLookup(ahost);
DoRemoteSocketPrepared(Client);
end //with/if
else begin
{$IFDEF LogHttpFlow}
LogFlow(Client, 'Reusing connection to %s:%s', [Client.RemoteHost,
Client.RemoteSocket.Port]);
{$ENDIF LogHttpFlow}
end;
{$IFDEF LogHttpFlow}
LogFlow(Client, 'Request: %s', [FirstEl(header, #13, -1)]);
{$ENDIF LogHttpFlow}
Client.Received := header;
end
else begin
Client.DestroyRemoteSocket;
Client.RemoteContent := returnContent;
end;
Client.GotHeader := true;
end; { TGpHttpProxy.ProcessHeader }
function TGpHttpProxy.ProcessHTTPHeader(Client: TGpHttpProxyClient; var
header, ahost,
aport, returnContent: string; var socketResetRequired: boolean): boolean;
function MakeUrl(aproto, auser, apass, ahost, aport, apath: string):
string;
begin
Result := aproto;
if Last(Result,1) = ':' then
Result := Result + '//'
else if Last(Result,1) <> '/' then
Result := Result + '://';
if auser <> '' then begin
Result := Result + auser;
if apass <> '' then
Result := Result + ':' + apass;
Result := Result + '@';
end;
Result := Result + ahost;
if (aport <> '') and (aport <> '80') then
Result := Result + ':' + aport;
Result := Result + apath;
end; { MakeUrl }
var
apass : string;
apath : string;
aproto : string;
auser : string;
command : string;
hdrHost : string;
ignoreNextHopProxy: boolean;
p1 : integer;
p2 : integer;
s : string;
url : string;
begin { TGpHttpProxy.ProcessHTTPHeader }
Result := false;
socketResetRequired := false;
// extract url from GET/POST header
s := header;
p1 := Pos(' ',s);
if p1 > 0 then begin
command := First(s,p1-1);
Delete(s,1,p1);
s := TrimLeft(s);
p2 := Pos(' ',s);
if p2 > 0 then begin
url := Copy(s,1,p2-1);
ParseURL(url,aproto,auser,apass,ahost,aport,apath);
if aport = '' then
aport := '80';
hdrHost := ExtractHeader(header,'Host');
returnContent := '';
ignoreNextHopProxy := false;
DoClientHeaderAvailable(Client,url,header,aproto,auser,apass,ahost,aport,
apath,hdrHost,ignoreNextHopProxy,returnContent);
if (NextHopHTTP.Address <> '') and (not ignoreNextHopProxy) and
(returnContent = '') then //replace host information with proxy
begin
Delete(header,p1+1,p2-1);
Insert(MakeUrl(aproto,auser,apass,ahost,aport,apath),header,p1+1);
if NextHopHTTP.Username <> '' then begin
// Insert 'Proxy-Authorization' header
p1 := Pos(CRLF+CRLF,header);
Insert(CRLF+'Proxy-Authorization: Basic '+
EncodeStr(encBase64,
NextHopHTTP.Username+':'+NextHopHTTP.Password),
header,p1);
end;
ReplaceHeader(header,'Host',hdrHost);
aport := IntToStr(FNextHopProxy[ptHTTP].Port);
ahost := FNextHopProxy[ptHTTP].Address;
Client.UsingNextHop := true;
end
else if SameText(command,'OPTIONS') and (ahost = '*') then
Exit
else begin
socketResetRequired :=
assigned(Client.RemoteSocket) and
((not SameText(Client.RemoteHost, ahost)) or
(Client.RemoteSocket.Port <> aport));
// Any of the URL parts may have changed in the event handler -
modify the header.
Delete(header,p1+1,p2-1);
if SameText(command,'OPTIONS') then
Insert('*', header, p1+1)
else if ((Client.NumRequests <= 1) and (Pos('HTTP/1.0',
FirstEl(header, #13, -1)) > 0)) or socketResetRequired then
Insert(apath, header, p1+1)
else
Insert(aproto+'://'+ahost+IFF(aport<>'80',':'+aport,'')+apath,
header, p1+1);
ReplaceHeader(header, 'Host', hdrHost);
if auser <> '' then begin
// Insert 'Authorization' header
p1 := Pos(CRLF+CRLF,header);
Insert(CRLF+'Authorization: Basic '+EncodeStr(encBase64, auser+
':'+apass),
header,p1);
end;
Client.ProxyConnection := ExtractHeader(header, 'Proxy-connection');
Client.UsingNextHop := false;
end;
Result := true;
end; //else p2 > 0
end; //else p1 > 0
end; { TGpHttpProxy.ProcessHTTPHeader }
Hope that helps.
Primoz
-----Original Message-----
From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On
Behalf Of S.Korotky
Sent: Sunday, September 21, 2008 9:56 PM
To: ICS support mailing
Subject: Re: [twsocket] GpHTTPProxy doesn't work correctly
Hello Stephane,
Yes, I've managed to locate the place where the problems are "initiated",
this
is ProcessHeader procedure. It processes only the very first http-header in
an established connection and bypasses all the others. So, if a browser
keeps the connections and uses them to request pages from different sites,
404 errors are produced or incorrect content is shown. I don't think
it will be easy to write a quick patch without proper processing of http 1.1
data on per-document basis. Perhaps, if it'll be possible to make a browser
believe, that it is _not_ connected to a proxy, it will not re-use the same
connection for different sites, but will establish new ones. I don't
remember if a http-header exists which allows for doing so, if included in
http response header to the browser (this is not the thing the
Proxy-Connection does).
Best wishes
Stanislav Korotky
----- Original Message -----
From: "Stéphane CHADEYRON" <[EMAIL PROTECTED]>
To: "ICS support mailing" <[email protected]>
Sent: Saturday, September 20, 2008 10:03 PM
Subject: Re: [twsocket] GpHTTPProxy doesn't work correctly
> Hello Stanislav,
>
> I have a user case: with the web-site :www.youtube.com
> Impossible display this web site correct.
>
> Other case but not systematic:
> 1. write in the address bar in your navigator (with the proxy) the url:
> www.google.com
> 2. write in the address bar in your navigator (with the proxy) the url:
> www.clubic.com
> 3. write again in the address bar in your navigator (with the proxy) the
> url: www.clubic.com
> > result: there is a other page... google or smartserver or error...
>
> Thank you for your help.
>
> Best regards,
>
> Stephan
>
> --
> To unsubscribe or change your settings for TWSocket mailing list
> please goto http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket
> Visit our website at http://www.overbyte.be
>
--
To unsubscribe or change your settings for TWSocket mailing list
please goto http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket
Visit our website at http://www.overbyte.be
--
To unsubscribe or change your settings for TWSocket mailing list
please goto http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket
Visit our website at http://www.overbyte.be