Search code examples
delphiindy10indy-9

From Indy 9 to Indy 10


I need your help:

A. Indy 9.

AThread.OutboundClient.Write(AddHeader(athread.netdata,'Connection: Keep-Alive'));  

AThread.OutboundClient.Write(stringreplace(athread.netdata,#13#10#13#10,#13#10 + 'Connection: Keep-Alive' + #13#10 + #13#10,[rfreplaceall]));

B. Indy 10.

Can somebody here tell me what's the right indy 10 code based on the above indy 9 code. I tried to use this, but does not work at all:

....
var Netdata:String;
....

TIdMappedPortContext(AContext).OutboundClient.IOHandler.Write(AddHeader(netbyte(netdata,'Connection: Keep-Alive')));

TIdMappedPortContext(AContext).OutboundClient.IOHandler.Write(netbyte(netdata,StringReplace(netstring(AContext,#13#10#13#10,#13#10 + 'Connection: Keep-Alive' + #13#10 + #13#10,[rfreplaceall])); )

Solution

  • NetData is a property of TIdMappedPortContext, eg:

    TIdMappedPortContext(AContext).OutboundClient.IOHandler.Write(AddHeader(BytesToString(TIdMappedPortContext(AContext).NetData), 'Connection: Keep-Alive'));  
    
    TIdMappedPortContext(AContext).OutboundClient.IOHandler.Write(StringReplace(BytesToString(TIdMappedPortContext(AContext).NetData), #13#10#13#10, #13#10 + 'Connection: Keep-Alive' + #13#10 + #13#10, [rfReplaceAll]));
    

    In the code you showed, your use of netbyte() and netstring() does make it seem like you are trying to account for the fact that NetData is now a byte array instead of a String. But either way, you are not handling this situation very well in general. In both Indy 9 and 10, this type of code is not a reliable way to modify HTTP headers passing through TIdMappedPortTCP. TIdMappedPortTCP is a straight pass-through of raw data, it has no concept of the HTTP protocol. The data stored in NetData is arbitrary, it could contain bytes for any portion of an HTTP message (or multiple messages) that just happen to be on the socket at that particular moment. So you cannot rely on there being valid complete HTTP messages in each NetData.

    If you are going to use TIdMappedPortTCP in this manner, you need to maintain a buffer of all data received from a client, and then parse that buffer each time you add new data to it. You need to know where each HTTP message ends and the next HTTP message begins, and also where the HTTP headers end and the HTTP body begins within in each HTTP message. Only then can you safely inject custom HTTP headers into the conversation. That is much more advanced logic then what you have shown here.

    With that said, Indy has a TIdHTTPProxyServer component, you should be using that instead of TIdMappedPortTCP, eg:

    Indy 9:

    // OnHTTPHeaders event handler...
    procedure TForm1.IdHTTPProxyServer1HTTPHeaders(ASender: TIdHTTPProxyServerThread; const ASource: TIdHTTPSource; const ADocument: string; AHeaders: TIdHeaderList);
    begin
      if ASource = httpBrowser then
        AHeaders.Values['Connection'] := 'Keep-Alive';
    end;
    

    Indy 10:

    // OnHTTPBeforeCommand event handler...
    procedure TForm1.IdHTTPProxyServer1HTTPBeforeCommand(AContext: TIdHTTPProxyServerContext);
    begin
      if AContext.TransferSource = tsClient then
        AContext.Headers.Values['Connection'] := 'Keep-Alive';
    end;
    

    You can then configure your HTTP client to connect to TIdHTTPProxyServer as an HTTP proxy, instead of connecting to TIdMappedPortTCP as if it were the actual HTTP server.