tIdHttpServer - EidConnClosed prima di inviare una risposta al POST
-
26-09-2019 - |
Domanda
Sto avendo difficoltà implementare un server HTTP con indy 10 in Delphi 2007.
Ho creato un semplice gestore di eventi per l'evento CommandGet.
Quando si risponde ai dati inviati utilizzando il metodo GET posso analizzare i params e sul retro i dati di invio XML senza problemi. (Vedi codice qui sotto)
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);
Quando provo a rispondere ai dati che vengono inviati tramite un POST la risposta non viene mai inviata da Indy, invece un EidConnClosedGracefully sia aumentata di TIdIOHandler.WriteDirect formano la linea di CheckForDisconnect (true, true). ecco come sto gestire i dati POST in arrivo
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);
Ho usato Wireshark per vedere cosa sta succedendo e sembra che Indy è l'invio di un ACK indietro prima che la risposta viene inviata e causando al cliente di disconnessione.
per testare questo I set-up Apache con PHP e ha scritto uno script PHP per fare lo stesso lavoro e tutto funziona bene, la differenza sono i dati POST è risposto con il contenuto della risposta non un ACK.
qualche suggerimento su come risolvere questo in modo da rispondere ai dati POST e GET.
mi sono bloccato con questo ora, come si può vedere da questa traccia Wireshark (cliccare sul link per un'immagine) Ho aumentato il timeout a 20 secondi. e la sua ancora non funziona. Ho intenzione di fare un po 'di più indagini. e vedere cosa riesco a scoprire. Il suo aspetto di Indy pensa che la disconnessione è verificato prima che abbia
Soluzione
Sembra che il http viene inviato come
Transfer-Encoding: chunked
Quindi non v'è alcun content-length. ma la versione di Indy sto usando non supporta questa modalità.
Altri suggerimenti
ACK non sono inviati da Indy sé, ma dal socket sottostante invece, e anche allora solo in risposta ai pacchetti ricevuti dall'altra parte. EIdConnClosedGracefully significa che il client è intenzionalmente di scollegare la presa sulla sua fine prima della lattina server ha inviato i suoi dati di risposta. Il fatto che un ACK è presente aiuta a dimostrare che (il socket è probabile ACK'ing pacchetto FIN del cliente durante la disconnessione).