Autor Beitrag
Stephan.Woebbeking
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 97



BeitragVerfasst: Mi 12.09.12 15:58 
Hallo,

ich habe nach wie vor Probleme mit meinem TIdHTTP. Es gibt zu einem ähnlichen Thema auch schon einen Thread hier; den konnte ich leider noch nicht ganz lösen und das Problem ist auch noch etwas anders gelagert, wenn es auch "die gleiche Ecke" ist...

Ich benutze eine Instanz von einem TIdHTTP (Instanziierung erfolgt im Code, nicht über die Oberfläche) und sende dann etliches an Requests. Erst einen Post, dann bis über 80 Put Anfragen (mit Senden von mehreren MB an Daten) und schlußendlich noch einen Post um die Konversation abzubauen.

Bis auf den letzten Post läuft das Ganze über EIN und DENSELBEN Port, der letzte Post läuft über einen anderen Port. Das bringt den Server dazu, die Verbindung als nicht abgeschlossen zu betrachten, die Daten zu verwerfen und den Post als unzulässig (Bad Request) abzulehnen. Ausgelöst wird es durch - nehme ich an - ein gesetztes "FIN" Flag im letzten PUT, neue SYN Pakete und dann kommt der Post auf einem neuen Port.

Hat jemand eine Idee für mich, wie ich dieses Verhalten kontrollieren kann? Ich habe keine Angaben gefunden, mit denen ich den Verbindungsabbau bzw. die Weiterverwendung anregen könnte. Weder verstehe ich, warum die vorhergehenden Requests alle über eine Verbindung laufen, noch, warum der letzte Request über eine andere gesendet wird?

Ein bischen Code, ob's hilft???

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
  // Preparations
[...]
  // Open the firmware update file
[...]
  // Prepare the HTTP request
  data := TStringList.Create;
  data.Add( 'duration=' + IntToStr( packListPKG.Duration ) );
  data.Add( 'start' );
[...]
  Application.ProcessMessages;
  httpConnector.HTTPOptions := httpConnector.HTTPOptions + [ hoKeepOrigProtocol ];
  try
    httpConnector.Post( UPDATE9046_HTTP_PROTOCOL + Connector.ip + ' ' + UPDATE9046_POST_UPD_START, data );
  except on E: Exception do
    MemoLogger.AddToLog( E.Message + '  ' + IntToStr( httpConnector.ResponseCode ) + ' : ' + httpConnector.ResponseText );
  end;
[...]
  line := httpConnector.Response.Location;
[...]
  data.Free;
[...]
  for a := 0 to {packListPKG.Count - 1} 0 do begin
    stream2.Clear;
[...]
    httpConnector.Request.ContentType := UPDATE9046_CONTENT_TYPE + ' duration=' + IntToStr( pInfo.Duration ) + '; length=' + IntToStr( pInfo.LengthFc ) + '; md5sum=' + pInfo.MD5Sum + '; version=' + IntToStr( pInfo.Version );
    Application.ProcessMessages;
    httpConnector.Put( line, stream2 );
[...]
    logger.Debug( 'Result: ' + httpConnector.Response.ResponseText );
    if ( httpConnector.Response.ResponseCode = 204 ) then
      MmoUpdate.Lines.Strings[ MmoUpdate.Lines.Count - 1 ] := Format( 'Completed: %s', [ pInfo.Name ] )
    else
      MmoUpdate.Lines.Strings[ MmoUpdate.Lines.Count - 1 ] := Format( 'Error on upload: %s', [ pInfo.Name ] );
[...]
  end;
[...]
  data := TStringList.Create;
  data.Add( 'finalise' );
  httpConnector.
  httpConnector.Post( location, data );
[...]
  logger.Debug( IntToStr( httpConnector.ResponseCode ) + ' ' + httpConnector.ResponseText );
  // Clean up
  data.Free;
[...]


Danke & viele Grüße,
Stephan
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1321
Erhaltene Danke: 117

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Sa 15.09.12 11:46 
[sarkassmus]Wie Du siehst ist mit der schier unglaublichen Menge an Code bisher jeder derat überfordert gewesen das es keiner geschafft hat Dir zu antworten.[/sarkassmus]
Wesentliche Fragen:
Was ist das für ein Server, von der Stange oder selber gebaut?
Was wird zwischen den Post's/Put's gemacht? (Könnte es passiert sein das Speicher der Komponente überschrieben wird?)
Hast Du mal probiert die Komponente für jede Anftrage neu zu erstellen?
Könnte ein Firewall/Proxy im Weg sein?

Ist das Projekt kommerziell? Wenn ja würde ich Dir raten mal bei /NSoftware vorbei zu sehen. Denen ihre HTTP Komponente habe ich schon mehfach erfolgreich verwendet. Die non-SSL Varianten sind in neueren Versionen von Delphi (XE+) sogar mit dabei soweit ich gesehen habe.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10181
Erhaltene Danke: 1254

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Di 18.09.12 23:56 
Moin!

Vorab, ich bin nicht der WebDAV-Experte (da du mit PUT-Requests arbeitest, gehe ich mal davon aus, dass das WebDAV ist).

user profile iconStephan.Woebbeking hat folgendes geschrieben Zum zitierten Posting springen:
Ich benutze eine Instanz von einem TIdHTTP (Instanziierung erfolgt im Code, nicht über die Oberfläche) und sende dann etliches an Requests. Erst einen Post, dann bis über 80 Put Anfragen (mit Senden von mehreren MB an Daten) und schlußendlich noch einen Post um die Konversation abzubauen.

Bis auf den letzten Post läuft das Ganze über EIN und DENSELBEN Port, der letzte Post läuft über einen anderen Port.
[...]
Hat jemand eine Idee für mich, wie ich dieses Verhalten kontrollieren kann?
Ich nehme mal an, dass du mit "Port" den Client-Absender-Port für die Socket-Verbindungen meinst und die Auswahl dieses Ports der WSA überlassen hast (was der Standard ist und auch so sein sollte, alles andere ist mit großem Aufwand und Problemen verbunden). :nixweiss:

Kurz gesagt: HTTP, die Grundlage für WebDAV, ist ein zustandsloses Protokoll, es gibt da keine Session oder sowas, deshalb ist jeder Request eine komplette TCP-Connection mit Auf- und Abbau der TCP-Verbindung. Folglich ist es eher unwahrscheinlich, dass dann auch immer der gleiche TCP-Client-Absender-Port vom IP-Stack gewählt wird. Wenn viele Anwendungen im Netzwerk aktiv sind, dürfte es sogar eher die Ausnahme sein, dass du zufällig den gleichen Port für eine Verbindung zugeteilt kriegst. :idea:

Deshalb finde ich es sehr verwunderlich, dass du annimmst:
user profile iconStephan.Woebbeking hat folgendes geschrieben Zum zitierten Posting springen:
Das bringt den Server dazu, die Verbindung als nicht abgeschlossen zu betrachten, die Daten zu verwerfen und den Post als unzulässig (Bad Request) abzulehnen.
Eigentlich kann das nix mit dem Port zu tun haben. Wie ist denn die exakte Spezifikation zu diesem Protokoll, dass du da verwendest? Sowas aussergewöhnliches müsste doch explizit erwähnt sein! :les:

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Stephan.Woebbeking Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 97



BeitragVerfasst: Mo 22.10.12 17:48 
Hallo, danke schon mal für die Anregungen,

in einem anderen Forum hat sich die Diskussion in eine andere Richtung entwickelt die gut ist, aber auch noch keine Lösung gebracht hat:
forums2.atozed.com/v...6&p=31387#p31387

Aber jetzt hierzu:

@Sinspin:
Der Server ist ein embedded Gerät und steuert eine komplexe Hardware an. Implementiert ist er auf einem Ubuntu, falls das hilft?
Ich habe den Code weiter verkürzt, so dass also zwischendurch eingentlich nichts anderes passiert... Dagegen spricht auch, dass der gesamte Upload (bis zu 80 einzelne Dateien) alle über denselben Port laufen.
Wenn ich die Komponente neu erstelle und dann die Verbindung "per Standard" aufbaue, dann kommuniziert der Client ja immer auf einem anderen Port. Und das wird halt vom Server als "illegal" gewertet.
Scheint mir unwahrscheinlich, ich habe einen linksys Router als Switch dazwischen (als DHCP), ansonsten physisch nichts. Die Firewall ist ein echt hartes Ärgernis, aber die stelle ich im lokalen Netzwerk immer komplett aus.
Yep, ich nehm zwar kein Geld dafür aber ich mach das beruflich - sonst hätte ich mir vermutlich was lustigeres gesucht. ;)

@Narses
Nein ist nicht WebDAV, die PUTs werden einfach verwendet um Firmware Dateien auf einen Standard Web Server zu legen. Was im Server damit passiert ist für mich "out of scope" - vor allem ist der Nachweis bereits erbracht, dass das funktioniert.
Ja, die Auswahl überlasse ich der Komponente, aber er darf sich trotzdem nicht ändern (der Server ist da sehr genau). Das klappt ja auch für bis zu 80 Dateien ganz gut, lediglich für den letzten Post nutzt die Komponente mit einem Male einen anderen Port... Insbesondere dazu ist auch der o.g. Link zu "forums2.atoz.com" sehr interessant.


Zur Vervollständigung: Ich habe den Code weiter verkürzt und kann es jetzt so darstellen:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
var
  data: TStringList;
  line, tmpFileName: String;
  a, pos1: Integer;
  dataTransferred: Cardinal;
  stream2: TMemoryStream;
  pInfo: TEMPackageInfo;
  buffer2: PChar;
  tStart: Extended;
  v1, v2, v3, v4: Real;
begin
  // Prepare the HTTP request
  data := TStringList.Create;
  data.Add( 'duration=0' );
  data.Add( 'start' );
  // Switch EM9046 to update mode
  MemoLogger.AddToLog( 'Please wait for EM9046 to switch to update mode!' );
  Application.ProcessMessages;
  httpConnector.ProtocolVersion := pv1_1;
  httpConnector.HTTPOptions := httpConnector.HTTPOptions + [ hoKeepOrigProtocol ];
  try
    httpConnector.Post( UPDATE9046_HTTP_PROTOCOL + Connector.ip + ' ' + UPDATE9046_POST_UPD_START, data );                        // First POST HTTP/1.1 201 Created
    // http://192.168.1.102 /software/update
  except on E: Exception do
    MemoLogger.AddToLog( E.Message + '  ' + IntToStr( httpConnector.ResponseCode ) + ' : ' + httpConnector.ResponseText );
  end;
  MemoLogger.AddToLog( 'Response.Connection: ' + httpConnector.Response.Connection + ' Response.KeepAlive: ' + BoolToStr( httpConnector.Response.KeepAlive, True ) + ' Response.ProxyConnection: ' + httpConnector.Response.ProxyConnection );
  // Response.Connection: Keep-Alive Response.KeepAlive: True Response.ProxyConnection:
  Sleep( 300 );
  Application.ProcessMessages;
  line := httpConnector.Response.Location;
  pos1 := Pos( UPDATE9046_HTTP_PROTOCOL, line );
  pos1 := PosEx( '/', line, pos1 + Length( UPDATE9046_HTTP_PROTOCOL ) );
  location := RightStr( line, Length( line ) - pos1 + 1 );
  logger.Debug( 'Location: ' + location );
  Sleep( 300 );
  Application.ProcessMessages;
  // Clean up
  data.Free;
  // Finalize update
  MmoUpdateWarning.Visible := True;
  MemoLogger.AddToLog( '+++ W A R N I N G +++ Wait for receiver to finalize; takes up to 1 hour!' );
  data := TStringList.Create;
  data.Add( 'finalise' );
  Sleep( 300 );
  Application.ProcessMessages;
  try
    httpConnector.Post( UPDATE9046_HTTP_PROTOCOL + Connector.ip + ' ' + location, data );                                                                                         // Second POST HTTP/1.1 409 Conflict
    // http://192.168.1.102 /software/update/gMPhZars
  except on E: Exception do
    MemoLogger.AddToLog( E.Message + '  ' + IntToStr( httpConnector.ResponseCode ) + ' : ' + httpConnector.ResponseText );
  end;
  MemoLogger.AddToLog( 'Response.Connection: ' + httpConnector.Response.Connection + ' Response.KeepAlive: ' + BoolToStr( httpConnector.Response.KeepAlive, True ) + ' Response.ProxyConnection: ' + httpConnector.Response.ProxyConnection );
  // Response.Connection: close Response.KeepAlive: False Response.ProxyConnection:
  MemoLogger.AddToLog( httpConnector.Response.Connection );
  logger.Debug( IntToStr( httpConnector.ResponseCode ) + ' ' + httpConnector.ResponseText );
  // Clean up
  data.Free;
end;


Der "first" und "second" POST erfolgt über abweichende Port Nummern, das dürfte m.E. nicht passieren.

Ich hab hier auch eine .pcap Datei angefertigt. Da ich die in einem Forum nicht anfügen kann, hab ich sie ins Web gelegt:
Moderiert von user profile iconNarses: Extern gelinkte Datei als ZIP-Anhang hochgeladen.
Hoffe sie ist zugreifbar? Die wichtigsten Pakete darin:

Package 27 - first contact from software client to the device
package 39 - answer to the first contact - perfectly ok so far, both on port 54719
package 104 - now on port 54719 comes the FIN flag along, I suppose that's the problem?
package 108 - second request form the software client now on port 54722
package 113 - answer to the second request - as that came over different port, rejecting is "normal" behavior

Vielen Dank für alle Ideen, bisher bin ich noch auf dem falschen Weg, alle Versuche haben (noch) nichts verbessert.

vG,
Stephan
Einloggen, um Attachments anzusehen!
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10181
Erhaltene Danke: 1254

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Mo 22.10.12 22:27 
Moin!

user profile iconStephan.Woebbeking hat folgendes geschrieben Zum zitierten Posting springen:
in einem anderen Forum hat sich die Diskussion in eine andere Richtung entwickelt die gut ist, aber auch noch keine Lösung gebracht hat:
forums2.atozed.com/v...6&p=31387#p31387
Na, da hast du ja mit Remy Lebeau aus dem Indy-Team doch genau den Richtigen an der Hand! :zustimm: Wenn der das nicht gelöst kriegt, dann kannst du das vergessen. Was die Indy-Kompo angeht, steige ich hier aus. An dieser Stelle würde ich jetzt die Indies ignorieren und das selbst auf der WSA abwickeln (das sieht mir nach einer so speziell interpretierten "Version" der http-Spec aus :?, das würde ich um sicher zu gehen keiner Kompo mehr überlassen). :nixweiss:

Viel Erfolg noch, bin gespannt, was rauskommt. :beer:

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1321
Erhaltene Danke: 117

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Di 23.10.12 20:20 
Danke für Deine Ausführlichkeit. Der Normalfall bei einer Kommunikation zwischen HTTP Client und Server ist das für jede Datei die gesendet und empfangen wird eine neue Verbindung aufgebaut werden kann die dann unter Umständen auch einen neuen Port verwendet. Spontan fällt mir noch ein, es könnte eventuell einen Timeout geben nachdem die Komponente die Verbindung trennt. Bei einem neuen Transfer wird dann ein anderer Port verwendet. Hängt davon ab wie der Timeout gebaut ist und ob reale Zeitdifferenzen zuwischen den Anfragen bestehen.
Je nachdem was Du für eine Delphiversion einsetzt, könntest Du eine andere Komponente verwenden/testen, mit der ich bisher immer sehr gute Erfahrungen auch bei speziellen Anwendungsfällen gemacht habe. Ab XE sind von /N Software Komponenten mit enthalten. Vor XE könntest du es zumindest mit den Demoversionen mal testen. Das Paket nennt sich "IP Works!" Die Komponente im Package ist TipwHTTP. Wenn Du damit mal testen willst, ich kenne die Komponente recht gut (bzw. komme mit dem etwas eigenwilligen Design klar). Ansonsten, der Support von /N Sofware ist auch sehr gut, die helfen gerne.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
Stephan.Woebbeking Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 97



BeitragVerfasst: Do 25.10.12 12:08 
Hi, now I tried something else... I use the TTcpClient Component just for this test. I try to "simulate" the http protocol on top ot that and just send the data to make the server believe its a standard browser or something. But the server replies differently, so how does it know about? I have compared the POST package from the TIdHTTP (top) and from the TTcpClient (bottom) tests. That's the outcome:

see attachment

So from a binary point of view I only find differences in
- identification
- ip & port
- sequence
- acknowledgement
- window
- size
all of them I would say they don't account for the server to get confused. But somehow it does...

In general, is that an approach one could take if I can't handle the interruption of the session from the http component? Then, what field is most likely to cause the server to behave differently? Or do I have to take other packages as well into account? So then my assumption that the whole request (POST) is in this one package would be wrong?

I know, a lot of questions, but my aim is still the same: To establish one session which makes my server not complain any more... I know that a different software / component someone else I don't know has achieved that so I must be doable.

Thanks,
Stephan
Einloggen, um Attachments anzusehen!