tIdHttpServer - EidConnClosed avant d'envoyer une réponse à POST
-
26-09-2019 - |
Question
Je ne parviens pas mettre en œuvre un serveur HTTP avec indy 10 delphi 2007.
J'ai mis en place un gestionnaire d'événements simple pour l'événement CommandGet.
Lorsque vous répondez aux données envoyées en utilisant la méthode GET je peux analyser les params et envoyer des données XML retour sans problème. (Voir code ci-dessous)
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);
Lorsque je tente de répondre aux données envoyées à l'aide d'un POST la réponse est jamais envoyé par indy, au lieu d'un EidConnClosedGracefully est soulevée par TIdIOHandler.WriteDirect forment la ligne CheckForDisconnect (True, True). voici comment je manipuler les données POST entrant
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);
J'ai utilisé Wireshark pour voir ce qui se passe et il semble que indy envoie un retour ACK avant que la réponse est envoyée et provoque le client à se déconnecter.
pour tester ce que je installation Apache avec PHP et a écrit un script PHP pour faire le même travail et tout fonctionne bien, la différence est que les données POST est répondu à la teneur en réponse pas un accusé de réception.
des suggestions sur la façon de résoudre ce donc je répondre aux données POST ainsi que GET.
Je suis coincé avec cela maintenant, comme vous pouvez le voir sur cette trace de Wireshark (cliquez sur le lien pour l'image) j'ai augmenté le délai d'attente à 20 secondes. et son ne fonctionne toujours pas. Je vais faire quelques autres enquêtes. et voir ce que je peux trouver. Son air d'Indy pense que la déconnexion a eu lieu avant qu'il ait
La solution
On dirait que le http est envoyé comme
Transfer-Encoding: chunked
Par conséquent, il n'y a pas de longueur de contenu. mais la version d'Indy J'utilise ne prend pas en charge ce mode.
Autres conseils
ACKs ne sont pas envoyés par Indy lui-même, mais par la prise sous-jacente à la place, et même alors, seulement en réponse à des paquets reçus de l'autre partie. EIdConnClosedGracefully signifie que le client est volontairement la prise de débrancher son extrémité avant votre serveur peut envoyer ses données de réponse. Le fait qu'un accusé de réception est présent aide à prouver que (la prise est probablement ACK'ing paquet FIN du client lors de la déconnexion).