Search code examples
delphidelphi-2007indyhttpserverindy10

tIdHttpServer - EidConnClosed before sending a reply to POST


I am having trouble implementing a HTTP server with indy 10 in delphi 2007.

I have set up a simple event handler for the CommandGet event.

When replying to data sent using the GET method I can parse the params and send XML data back with no problems. (see code below)

    Download := ARequestInfo.Params.Values['dld'];
    Config := ARequestInfo.Params.Values['config'];
    Flash := ARequestInfo.Params.Values['flash'];
    Employees := ARequestInfo.Params.Values['employees'];
    Schedule := ARequestInfo.Params.Values['schedules'];
    AppTables := ARequestInfo.Params.Values['apptables'];

    Heartbeat :=  NewHeartbeat;

    Heartbeat.Version.Dld := Download;
    Heartbeat.Version.Config := Config;
    Heartbeat.Version.Flash := Flash;
    Heartbeat.Version.Employee := Employees;
    Heartbeat.Version.Schedule := Schedule;
    Heartbeat.Version.AppTables := AppTables;

    AResponseInfo.ContentType := 'application/xml';
    AResponseInfo.ResponseNo := 200;
    AResponseInfo.ContentText := '<?xml version="1.0" encoding="utf-8"?>' +
      #13+#10 + FormatXMLData(Heartbeat.XML);

When I try to reply to the data that is sent using a POST the response is never sent by indy, instead a EidConnClosedGracefully is raised by TIdIOHandler.WriteDirect form the CheckForDisconnect(True, True) line. here is how i'm handling the incoming POST data

    XMLDocument1.xml.Clear;
    XMLDocument1.Active := True;
    XMLDocument1.XML.text := ARequestInfo.FormParams;

    SynMemo1.Lines.Add(ARequestInfo.FormParams);
    SynMemo1.Lines.Add(#13+#10);

    if XMLDocument1.XML.Count > 0 then
    begin
      XMLDocument1.XML.Delete(0);
      XMLDocument1.XML.Delete(0);

      for i := pred(xmldocument1.xml.count) downto 0 do
      begin
        stmp := XMLDocument1.XML.Strings[i];

        if Length(stmp) > 0 then
        begin
          if Copy(stmp,1,1) = '<' then
            break
          else
            XMLDocument1.XML.Delete(i);
        end
        else
          XMLDocument1.XML.Delete(i);

      end;

      XMLDocument1.XML.Text := StringReplace(XMLDocument1.XML.Text,
        '<Punches ', '<Punches xmlns="http://ats/punch" ', [rfReplaceAll]);



    end;

    Punch := GetPunches(XMLDocument1);

    PunchReply := NewOperationStatus;
    PunchReply.Uid := Punch.Uid;
    PunchReply.NodeValue := 'OK';

    stmp := '<?xml version="1.0" encoding="utf-8"?>' +
      #13+#10 + FormatXMLData(PunchReply.XML);
    SynMemo1.Lines.Add(stmp);
    SynMemo1.Lines.Add(#13+#10);

    AResponseInfo.ContentType := 'text/html';
    AResponseInfo.ContentStream := TStringStream.Create(stmp);

I have used wireshark to see what is happening and it looks like indy is sending an ACK back before the response is sent and causing the client to disconnect.

to test this I set-up Apache with PHP and wrote a PHP script to do the same job and everything works ok, The difference is the POST data is replied to with the response content not an ACK.

any suggestions on how to resolve this so I respond to the POST data as well as GET.


I'm stuck with this now, as you can see from this wireshark trace (click link for image) i have increased the timeout to 20 seconds. and its still not working. I'm going to do some more investigations. and see what I can find out. Its looking like Indy thinks the disconnect has occurred before it has

Click here for image


Solution

  • Looks like the http is being sent as

    Transfer-Encoding: chunked
    

    Therefore there is no content-length. but the version of Indy I am using doesn't support this mode.