Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Windows API: HTTP D11 vs. D10 (https://www.delphipraxis.net/213363-windows-api-http-d11-vs-d10.html)

looseleaf 18. Jul 2023 10:37

Windows API: HTTP D11 vs. D10
 
Liebe Gemeinde!

Wir siedeln gerade unsere D10 Anwendung auf D11. Wir haben eine Unit im Einsatz, die seit Jahren zuverläsig HTTP-Anfragen (vor allem HTTPS) ereldigt. Mit D11 bekommen wir immer wieder, dann aber gehäuft, die Rückmeldung HTTP/400 Bad Request. Betriebssysteme sind Windows 11, ein und dieselbe EXE funktioniert auf einem Computer, auf einem anderen nicht. Und irgendwann geht sie dann wieder.
Kopiere ich die URLs in den Webbrowser, funktioniert es immer, ich schließe daher ein Webserverproblem explizit aus.
Es sind keine URLs mit Parametern, z. B. einfach https://unserhostname/Service/serviceinfo.txt

Die verwendeten API Calls sind
InternetOpenA
InternetSetOptionA
InternetConnectA
HttpOpenRequestA
InternetQueryOptionA
InternetSetOptionA
HttpSendRequestA
InternetReadFile

Die Exception taucht beim HttpSendRequestA auf, liefert aber noch eine passende Server-Fehlermeldung. An die Serverlogs komme ich leider nicht ran.

Hat irgendjemand eine sinnvolle Idee, wo ich überhaupt anfangen soll, oder vielleicht schon einmal von so etwas gehört?

Ratlos

Klaus01 18. Jul 2023 10:54

AW: Windows API: HTTP D11 vs. D10
 
.. würde es helfen, wenn Du den Traffic mit wireshark tracen würdest?

Grüße
Klaus

looseleaf 18. Jul 2023 11:02

AW: Windows API: HTTP D11 vs. D10
 
Zitat:

Zitat von Klaus01 (Beitrag 1524667)
.. würde es helfen, wenn Du den Traffic mit wireshark tracen würdest?

Grüße
Klaus

Nicht bei HTTPS, und die fraglichen Reqeusts sind alle HTTPS. Zumindest inhaltlich (gesendete Header) hab ich keine Chance.
Aber ich ziehe gerade lokal einen Apachen hoch und werde die URLs mal dorthin umbiegen, dort bekomme ich dann wenigstens die Serverlogs.

Stefan

himitsu 18. Jul 2023 12:36

AW: Windows API: HTTP D11 vs. D10
 
Sollten die neueren TNetHTTPClient bzw. TNetHTTPRequest nicht auch HTTPS können? (mach es intern über Windows, bzw. auch für andere OS)

Also nicht so wie beim TIdHTTP, wo man womöglich erst noch TIdSSLIOHandlerSocketOpenSSL und eventuell paar DLLs mitbringen und anhängen muß.


Per se sollte es aber für die direkte Verwendung einer WinAPI keinen Unterschied machen, welche DelphiVersion es ist.
Und zwischen D10 und D11 sollte es auch keine großen Unterschiede geben, was z.B. die Einstellungen der PE oder des Windows-Manifests angeht, also was sich z.B. auf die Virtualisierung "alter" Programme auswirken würde (XP-Mode usw.). :gruebel:
[edit] stimmt ... ASLR ist in D11 nun aktiv

Uwe Raabe 18. Jul 2023 13:06

AW: Windows API: HTTP D11 vs. D10
 
Zitat:

Zitat von looseleaf (Beitrag 1524666)
ein und dieselbe EXE funktioniert auf einem Computer, auf einem anderen nicht. Und irgendwann geht sie dann wieder.

Könnte dann aber auch an ASLR liegen - das sorgt nämlich für ein verändertes Umfeld bei jedem Start. Einfach mal probeweise in den Linker-Optionen abschalten.

Sollte es damit dann funktionieren, liegt der Fehler aber nicht in dieser Einstellung, sondern im (vermutlich eigenen) Code. Das Flag macht ihn halt nur sichtbar. Ursache könnte z.B. die Verwendung von Integer sein, wo eigentlich Cardinal hingehört.

looseleaf 18. Jul 2023 13:09

AW: Windows API: HTTP D11 vs. D10
 
Zitat:

Zitat von himitsu (Beitrag 1524671)
Sollten die neueren TNetHTTPClient bzw. TNetHTTPRequest nicht auch HTTPS können? (mach es intern über Windows, bzw. auch für andere OS)

Also nicht so wie beim TIdHTTP, wo man womöglich erst noch TIdSSLIOHandlerSocketOpenSSL und eventuell paar DLLs mitbringen und anhängen muß.


Per se sollte es aber für die direkte Verwendung einer WinAPI keinen Unterschied machen, welche DelphiVersion es ist.
Und zwischen D10 und D11 sollte es auch keine großen Unterschiede geben, was z.B. die Einstellungen der PE oder des Windows-Manifests angeht, also was sich z.B. auf die Virtualisierung "alter" Programme auswirken würde (XP-Mode usw.). :gruebel:

Indy verwenden wir aus dem Grund seit Jahren nicht.
Was mich verwundert ist, dass es einmal geht und einmal nicht. Immer nach einem NEustart (bisher so beobachtet). Also einmal geht es zuverlässig während derselben Laufzeit, startet man neu, geht es vielleicht nicht oder schon. Aber immer bis zum Ende der Laufzeiten.

Stefan

looseleaf 18. Jul 2023 13:12

AW: Windows API: HTTP D11 vs. D10
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1524673)
Zitat:

Zitat von looseleaf (Beitrag 1524666)
ein und dieselbe EXE funktioniert auf einem Computer, auf einem anderen nicht. Und irgendwann geht sie dann wieder.

Könnte dann aber auch an ASLR liegen - das sorgt nämlich für ein verändertes Umfeld bei jedem Start. Einfach mal probeweise in den Linker-Optionen abschalten.

Sollte es damit dann funktionieren, liegt der Fehler aber nicht in dieser Einstellung, sondern im (vermutlich eigenen) Code. Das Flag macht ihn halt nur sichtbar. Ursache könnte z.B. die Verwendung von Integer sein, wo eigentlich Cardinal hingehört.


Danke für den Hinweis, ich werde das gleich ausprobieren. Und das würde auch erklären, dass es einmal (100% der Fälle zur selben Laufzeit) geht oder nicht geht. Ich setze einfach mal das ASLR auf false. Aber verstehe ich das jetzt richtig: Es kann sein, dass es jetzt nie geht?

Stefan

Uwe Raabe 18. Jul 2023 13:24

AW: Windows API: HTTP D11 vs. D10
 
Das R impliziert ja eine gewisse Zufälligkeit. Dass es nie geht ist somit genauso unwahrscheinlich wie dass es immer geht. (Wenn es denn überhaupt daran liegt)

looseleaf 18. Jul 2023 13:29

AW: Windows API: HTTP D11 vs. D10
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1524676)
Das R impliziert ja eine gewisse Zufälligkeit. Dass es nie geht ist somit genauso unwahrscheinlich wie dass es immer geht. (Wenn es denn überhaupt daran liegt)

Wenn ich es richtig verstehe, betrifft es aber immer nur das geladene Prozessimage sowie nachgeladene DLLs, die unterschiedliche zufällige Speicherbereiche zugewiesen bekommen. Wenn es aber mal läuft (und nicht dynamisch entladen oder geladen wird), dann würde alles an derselben Stelle bleiben? Insofenr verstünde ich, dass es bei einem Programmlauf geht, beim nächsten vielleicht nicht.

Andererseits weiß ich nicht, ob die Windows API für HTTP Requests dynamisch oder statisch geladen wird.

Nur zur Sicherheit: Wenn ich wirklcih einen HTTP/400 zurückbekommen, kann SSL nicht mehr das Problem sein, da ich ja schon das Backend erreiche, es würde mir also reichen, wenn ich den Request an eine HTTP-Seite umlenke und mit Wireshark nachschaue, was der Unterschied in den Headern ist, wenn es geht oder nicht geht. Valider Ansatz?

Stefan

Uwe Raabe 18. Jul 2023 13:32

AW: Windows API: HTTP D11 vs. D10
 
Ja, dann könnte man immerhin sehen, was am anderen Ende ankommt, und daraus weitere Schlüsse ziehen.

himitsu 18. Jul 2023 14:27

AW: Windows API: HTTP D11 vs. D10
 
Zitat:

Zitat von looseleaf (Beitrag 1524674)
Indy verwenden wir aus dem Grund seit Jahren nicht.

Die neueren TNetHTTPClient bzw. TNetHTTPRequest sind von Embarcadero (oder wo sie das auch immer her haben), aber jedenfalls nicht aus dem INDY-Projekt und sie sind auch Multiplatform. (leider nur HTTP, nur Client und kein Serverzeugs)

looseleaf 18. Jul 2023 14:37

AW: Windows API: HTTP D11 vs. D10
 
Zitat:

Zitat von himitsu (Beitrag 1524679)
Zitat:

Zitat von looseleaf (Beitrag 1524674)
Indy verwenden wir aus dem Grund seit Jahren nicht.

Die neueren TNetHTTPClient bzw. TNetHTTPRequest sind von Embarcadero (oder wo sie das auch immer her haben), aber jedenfalls nicht aus dem INDY-Projekt und sie sind auch Multiplatform. (leider nur HTTP, nur Client und kein Serverzeugs)

Danke, ich zaudere aber ein wenig, die bestehende Implementierung gegen eine andere Komponente zu ersetzen. Verwenden die den Zertifikatscache vom MSIE/Edge?

himitsu 18. Jul 2023 15:05

AW: Windows API: HTTP D11 vs. D10
 
Zitat:

Zitat von looseleaf (Beitrag 1524680)
Verwenden die den Zertifikatscache vom MSIE/Edge?

Ja, so weit ich das verstanden hatte.

Zitat:

Zitat von mjustin (Beitrag 1516345)
Das ist möglich, weil das Zertifikat über den Windows Zertifikatsspeicher geprüft wird.

https://www.delphipraxis.net/212095-...component.html
Wurde zumindestens von Mehreren so gesagt.

looseleaf 18. Jul 2023 15:05

AW: Windows API: HTTP D11 vs. D10
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1524678)
Ja, dann könnte man immerhin sehen, was am anderen Ende ankommt, und daraus weitere Schlüsse ziehen.

Ich glaub, ich weiß, wo es hakt. Der Accept-HEader liefert nicht nur */*, sondern danach noch eingies an Datenmüll.

Seit jeher ist die lokale Variable

var accept: Array[0..1] of PAnsiChar;
...
accept[0]:=PAnsiChar('*/*');
accept[1]:=PAnsiChar(#0);
...
hRequest := HttpOpenRequestA(hConn, 'GET', PAnsiChar(fUrlPath+fExtraInfo), HTTP_VERSION,
nil, @accept, connFlags, 42);


ich habe das auf packed array geändert, den Rest des Codes gleich gelassen (Zuweisung, PAnsiChar, HttpOpenRequestA), et voilà, es funktioniert.

Kann mir wer erklären, warum das bisher funktioniert hat?

himitsu 18. Jul 2023 15:09

AW: Windows API: HTTP D11 vs. D10
 
Zitat:

Zitat von looseleaf (Beitrag 1524682)
Ich glaub, ich weiß, wo es hakt. Der Accept-HEader liefert nicht nur */*, sondern danach noch eingies an Datenmüll.

PChar haben eine #0 hinten dran und Delphi-Strings aka LongStrings (also alles außer dem ShortString) sogar zwei implizite #0#0 (so lange der Entwickler nicht am Speicher rumpfuscht, ala BufferOverflow).


Array und Packed-Array sollten hier keinen Unterschied haben, da Pointer quasi immer packed sind (weil sie keine ungerade unausgerichtete Größe besitzen, also immer bereits ausgerichtet sind und es somit auch keine Lücke gibt)




Laut Dokumentation ist die #0 aber nicht ganz richtig.
Delphi-Quellcode:
accept[0] := PAnsiChar('*/*');
accept[1] := nil; // ein Zeiger auf NICHTS, während PChar(#0) ein Zeiger auf einen String aus einem #0 ist (eigentlich aus zwei #0, inkl. dem PChar-Terminator)
Zitat:

Code:
PCTSTR rgpszAcceptTypes[] = {_T("text/*"), NULL};
C++-NULL = Delphi-nil

looseleaf 18. Jul 2023 15:17

AW: Windows API: HTTP D11 vs. D10
 
Zitat:

Zitat von himitsu (Beitrag 1524683)
PChar haben eine #0 hinten dran und Delphi-Strings aka LongStrings (also alles außer dem ShortString) sogar zwei implizite #0#0 (so lange der Entwickler nicht am Speicher rumpfuscht, ala BufferOverflow).

Soweit klar, daher der Aufruf an PAnsiChar().
Ich habe im Delphi 10-Projekt auch einmal den Request auf HTTP umgebogen und erhalte immer einen sauberen Accept-Header. Keinen Datenmüll.

Kleine Beobachtung. Anscheinend war das Array immer etwas länger in D11, denn es kommen doch sehr regelmäßig Kommata im kaputten Accept-Header vor. Der Datenmüll ist auch immer derselbe, das Array hat offenbar 6 Elemente (das abschließende #0 nicht mitgezählt).

Zitat:

Zitat von himitsu (Beitrag 1524683)
Array und Packed-Array sollten hier keinen Unterschied haben, da Pointer quasi immer packed sind (weil sie keine ungerade unausgerichtete Größe besitzen, somit immer bereits ausgerichtet sind und es somit auch keine Lücke gibt)

Tja, de facto sehe ich aber einen messbaren Unterschied, der einzig und allein ander packed Deklaration hängt. Verstehen würde ich es aber sehr gerne. Irgendeine Compiler-Option dürfte da auch nicht im Spiel sein, zumindest unterscheiden sich die existierenden nicht zwischen D10 und D11.

:?:

himitsu 18. Jul 2023 15:59

AW: Windows API: HTTP D11 vs. D10
 
Delphi-Quellcode:
ShowMessage(SizeOf(accept).ToString);
sollte eigentlich das Gleiche liefern, egal ob
Delphi-Quellcode:
var accept: array[0..1] of PAnsiChar;
oder
Delphi-Quellcode:
var accept: packed array[0..1] of PAnsiChar;
.


Delphi-Quellcode:
accept[0] := '*/*';

Echte Konstanten (untypisierte Konstante) lassen sich auch direkt an PChar/PAnsiChar/PWideChar übergeben.

z.B. macht es keinen Unterschied, ob
Delphi-Quellcode:
ShellExecute(0, 'OPEN', ...
oder
Delphi-Quellcode:
ShellExecute(0, PChar('OPEN'), ...
.

looseleaf 19. Jul 2023 11:33

AW: Windows API: HTTP D11 vs. D10
 
Zitat:

Zitat von himitsu (Beitrag 1524686)
Delphi-Quellcode:
ShowMessage(SizeOf(accept).ToString);
sollte eigentlich das Gleiche liefern, egal ob
Delphi-Quellcode:
var accept: array[0..1] of PAnsiChar;
oder
Delphi-Quellcode:
var accept: packed array[0..1] of PAnsiChar;
.


Delphi-Quellcode:
accept[0] := '*/*';

Echte Konstanten (untypisierte Konstante) lassen sich auch direkt an PChar/PAnsiChar/PWideChar übergeben.

z.B. macht es keinen Unterschied, ob
Delphi-Quellcode:
ShellExecute(0, 'OPEN', ...
oder
Delphi-Quellcode:
ShellExecute(0, PChar('OPEN'), ...
.


Ja, tut es auch, immer 8. Ich verstehe absolut nicht, was hier das ursächliche Problem ist.

Danke jedenfalls für euer Feedback!

Stefan

Delphi.Narium 19. Jul 2023 17:21

AW: Windows API: HTTP D11 vs. D10
 
HTTP/400 Bad Request heißt einfach nur, dass das, was der Client an den Server schickt, vom Server nicht korrekt verarbeitet werden kann. "Irgendwas dadrin ist faul". Dies bezieht sich nicht nur auf die Url, sondern auf den gesamten Inhalt der Anfrage.
Zitat:

Ich glaub, ich weiß, wo es hakt. Der Accept-HEader liefert nicht nur */*, sondern danach noch eingies an Datenmüll.
Irgendwas davon irritiert den Server, deshalb seine Fehlermeldung.

Beim Aufbau des Headers muss irgendwas schieflaufen. Ein paar mögliche Ursachen wurden schon genannt. Und da das "Schieflaufen" sich bei jedem Programmstart irgendwie anders auswirkt, hast Du das Problem: Mal geht's, mal nicht, also das typische: Fehler ist nicht reproduzierbar, aber tritt regelmäßig auf.

Mögliche Ursache: Nicht sauber terminierte PChars, so dass da dann noch Teile dessen enthalten sind, was da gerade so zufällig im Arbeitsspeicher hinter dem PChar "rumliegt".

Wenn Du mal 'nen Header hier posten könntest und den vollständigen Quelltext zum Aufbau der Anfrage, wäre es eventuell möglich zu schauen, wo es da "klemmt".

looseleaf 20. Jul 2023 07:10

AW: Windows API: HTTP D11 vs. D10
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1524732)
HTTP/400 Bad Request heißt einfach nur, dass das, was der Client an den Server schickt, vom Server nicht korrekt verarbeitet werden kann. "Irgendwas dadrin ist faul". Dies bezieht sich nicht nur auf die Url, sondern auf den gesamten Inhalt der Anfrage.
Zitat:

Ich glaub, ich weiß, wo es hakt. Der Accept-HEader liefert nicht nur */*, sondern danach noch eingies an Datenmüll.
Irgendwas davon irritiert den Server, deshalb seine Fehlermeldung.

Beim Aufbau des Headers muss irgendwas schieflaufen. Ein paar mögliche Ursachen wurden schon genannt. Und da das "Schieflaufen" sich bei jedem Programmstart irgendwie anders auswirkt, hast Du das Problem: Mal geht's, mal nicht, also das typische: Fehler ist nicht reproduzierbar, aber tritt regelmäßig auf.

Mögliche Ursache: Nicht sauber terminierte PChars, so dass da dann noch Teile dessen enthalten sind, was da gerade so zufällig im Arbeitsspeicher hinter dem PChar "rumliegt".

Wenn Du mal 'nen Header hier posten könntest und den vollständigen Quelltext zum Aufbau der Anfrage, wäre es eventuell möglich zu schauen, wo es da "klemmt".

Der Code steht 1:1 oben, es sind nur die Deklaration, die Zuweisung und das Benutzen. An amderen Stellen wird "accept" nicht verwendet.
Den Header habe ich nicht mehr, hab den Debugcode schon rausgenommen, aber es war immer derselbe Datenmüll.

Wir verwenden es jetzt mit einem packed array und sind zufrieden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:14 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz