Hello, Primoz!

I think the modified code can not solve the problem on its own, without further
modifications. The reason for this is that ProcessHeader procedure is called 
from
ReceivedFromClient if and only if Client.GotHeader is false, but it is set to
true after the very first invocation of the ProcessHeader, so it will not be
called for all subsequent requests in a given connection.

Best wishes,
Stanislav Korotky.

----- Original Message ----- 
From: "Primož Gabrijelčič" <[EMAIL PROTECTED]>
To: "'ICS support mailing'" <twsocket@elists.org>
Sent: Monday, September 22, 2008 10:06 AM
Subject: Re: [twsocket] GpHTTPProxy doesn't work correctly


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" <twsocket@elists.org>
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

-- 
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

Reply via email to