|
Registriert seit: 27. Jun 2007 Ort: Köln 666 Beiträge Delphi 12 Athens |
#1
Hallo zusammen,
einer meiner Kunden hatte Probleme, mit unserer Anwendung auf eine REST-API zuzugreifen. Nachdem ich zunächst behauptet hatte, dass da irgendwas bei ihm an Firewalls oder Proxys falsch konfiguriert ist (weil wir das Problem bisher auch nie hatten), muss ich mittlerweile zugeben, dass er wohl recht hat und das Problem tatsächlich bei uns liegt. Das Problem ist, dass der Kunde tatsächlich einen Proxy im Netzwerk aktiv hat, Windows komplett auf "automatische Erkennung" eingestellt ist, aber Delphi diese automatische Erkennung nicht korrekt durchführt. Bevor ich jetzt einen Bugreport im QP aufmache, wollte ich hier noch einmal hören, ob ich vielleicht etwas übersehe, und auch, ob ihr vielleicht einen besseren Tipp für einen Workaround oder auch für die "richtige" Lösung habt. Das Problem besteht nach einem ersten Drüberschauen zumindest in Delphi 10.3 bis zum aktuellen 11.1 und liegt in der System.Net.HttpClient.Win. Dort gibt es die Methode TWinHTTPRequest.SetWinProxySettings und diese hat wiederum die Unter-Funktion GetProxyInfo, welche nach meiner Analyse fehlerhaft ist:
Delphi-Quellcode:
Meine Kommentare mit den *** sollten anzeigen, wo meiner Meinung nach der Fehler liegt und weshalb die automatische Proxy-Erkennung nicht funktioniert.
function GetProxyInfo(const AURL: string; var AProxy, AProxyBypass: string): Boolean;
var LAutoDetectProxy: Boolean; LpProxyConfig: PWinHTTPCurrentUserIEProxyConfig; LWinHttpProxyInfo: TWinHTTPProxyInfo; LAutoProxyOptions: TWinHTTPAutoProxyOptions; begin Result := True; AProxy := ''; AProxyBypass := ''; FillChar(LAutoProxyOptions, SizeOf(LAutoProxyOptions), 0); LpProxyConfig := TWinHttpLib.GetProxyConfig; if LpProxyConfig <> nil then begin if LpProxyConfig^.fAutoDetect then begin LAutoProxyOptions.dwFlags := WINHTTP_AUTOPROXY_AUTO_DETECT; LAutoProxyOptions.dwAutoDetectFlags := WINHTTP_AUTO_DETECT_TYPE_DHCP or WINHTTP_AUTO_DETECT_TYPE_DNS_A; // *** Obwohl die AutoDetect in der Proxy-Konfig aktiv ist, bleibt LAutoDetectProxy auf False! *** end; if LpProxyConfig^.lpszAutoConfigURL <> '' then begin LAutoProxyOptions.dwFlags := WINHTTP_AUTOPROXY_CONFIG_URL; LAutoProxyOptions.lpszAutoConfigUrl := LpProxyConfig^.lpszAutoConfigUrl; LAutoDetectProxy := True; end else begin // *** Wenn keine "AutoConfig"-URL angegeben ist, landet der Code hier, // *** auch wenn in der ProxyConfig "AutoDetect" angegeben ist. Dadurch // *** wird dann versucht, einen direkt eingestellten Proxy zu nehmen, // *** auch wenn keiner eingestellt ist. LAutoDetectProxy bleibt auf False. AProxy := LpProxyConfig^.lpszProxy; AProxyBypass := LpProxyConfig^.lpszProxyBypass; LAutoDetectProxy := False; end; end else begin // if the proxy configuration is not found then try to autodetect it (If the Internet Explorer settings are not configured for system accounts) LAutoProxyOptions.dwFlags := WINHTTP_AUTOPROXY_AUTO_DETECT; LAutoProxyOptions.dwAutoDetectFlags := WINHTTP_AUTO_DETECT_TYPE_DHCP or WINHTTP_AUTO_DETECT_TYPE_DNS_A; LAutoDetectProxy := True; end; if (AProxy = '') and LAutoDetectProxy then begin // *** Eigentlich müssten wir hier landen, aber wegen der falschen Abfragen oben, landen wir // *** nie hier. Folge: die entscheidende Funktion aus der WinHTTP-API, nämlich // *** WinHttpGetProxyForUrl wird nie aufgerufen! // From https://msdn.microsoft.com/en-us/library/aa383153%28VS.85%29.aspx // Try with fAutoLogonIfChallenged parameter set to false, if ERROR_WINHTTP_LOGIN_FAILURE then try // with fAutoLogonIfChallenged parameter set to true. LAutoProxyOptions.fAutoLogonIfChallenged := False; if WinHttpGetProxyForUrl(LClient.FWSession, LPCWSTR(AURL), LAutoProxyOptions, LWinHttpProxyInfo) then begin AProxy := LWinHttpProxyInfo.lpszProxy; AProxyBypass := LWinHttpProxyInfo.lpszProxyBypass; end else begin if GetLastError = ERROR_WINHTTP_LOGIN_FAILURE then begin LAutoProxyOptions.fAutoLogonIfChallenged := True; if WinHttpGetProxyForUrl(LClient.FWSession, LPCWSTR(AURL), LAutoProxyOptions, LWinHttpProxyInfo) then begin AProxy := LWinHttpProxyInfo.lpszProxy; AProxyBypass := LWinHttpProxyInfo.lpszProxyBypass; end else Result := False; end else Result := False; end; end; if AProxy = '' then Result := False; end; Eine einfache Lösung sieht so aus:
Delphi-Quellcode:
Mit dieser einfachen Änderung funktioniert es tatsächlich beim Kunden. "Richtiger" wäre wahrscheinlich etwas in diese Richtung:
function GetProxyInfo(const AURL: string; var AProxy, AProxyBypass: string): Boolean;
var LAutoDetectProxy: Boolean; LpProxyConfig: PWinHTTPCurrentUserIEProxyConfig; LWinHttpProxyInfo: TWinHTTPProxyInfo; LAutoProxyOptions: TWinHTTPAutoProxyOptions; begin Result := True; AProxy := ''; AProxyBypass := ''; FillChar(LAutoProxyOptions, SizeOf(LAutoProxyOptions), 0); LpProxyConfig := TWinHttpLib.GetProxyConfig; if LpProxyConfig <> nil then begin if LpProxyConfig^.fAutoDetect then begin LAutoProxyOptions.dwFlags := WINHTTP_AUTOPROXY_AUTO_DETECT; LAutoProxyOptions.dwAutoDetectFlags := WINHTTP_AUTO_DETECT_TYPE_DHCP or WINHTTP_AUTO_DETECT_TYPE_DNS_A; end; if LpProxyConfig^.lpszAutoConfigURL <> '' then begin LAutoProxyOptions.dwFlags := WINHTTP_AUTOPROXY_CONFIG_URL; LAutoProxyOptions.lpszAutoConfigUrl := LpProxyConfig^.lpszAutoConfigUrl; LAutoDetectProxy := True; end else begin AProxy := LpProxyConfig^.lpszProxy; AProxyBypass := LpProxyConfig^.lpszProxyBypass; // *** hier die einfache Änderung: haben wir keinen manuellen Proxy bekommen, // *** dann sorgen wir hier dafür, dass wir später in dem Block landen, in dem // *** GetProxyForURL aufgerufen wird LAutoDetectProxy := AProxy = ''; end; end else [... weiter wie oben ...]
Delphi-Quellcode:
Soweit, das, was ich rausgefunden habe. Ist für mich immer recht schwer zu testen, weil ich im Büro bei mir ohne Proxy arbeite, aber das Ergebnis vom Kunden war mit der Änderung (und ein paar Debug-Ausgaben) schon sehr eindeutig. Oder übersehe ich etwas?
function GetProxyInfo(const AURL: string; var AProxy, AProxyBypass: string): Boolean;
var LAutoDetectProxy: Boolean; LpProxyConfig: PWinHTTPCurrentUserIEProxyConfig; LWinHttpProxyInfo: TWinHTTPProxyInfo; LAutoProxyOptions: TWinHTTPAutoProxyOptions; begin Result := True; AProxy := ''; AProxyBypass := ''; FillChar(LAutoProxyOptions, SizeOf(LAutoProxyOptions), 0); LpProxyConfig := TWinHttpLib.GetProxyConfig; if LpProxyConfig <> nil then begin // *** AutoDetect mal klar initialisieren LAutoDetectProxy := False; if LpProxyConfig^.fAutoDetect then begin LAutoProxyOptions.dwFlags := WINHTTP_AUTOPROXY_AUTO_DETECT; LAutoProxyOptions.dwAutoDetectFlags := WINHTTP_AUTO_DETECT_TYPE_DHCP or WINHTTP_AUTO_DETECT_TYPE_DNS_A; // *** AutoDetect hier auch tatsächlich aktivieren, wenn es in der Config so steht! LAutoDetectProxy := True; end; if LpProxyConfig^.lpszAutoConfigURL <> '' then begin LAutoProxyOptions.dwFlags := WINHTTP_AUTOPROXY_CONFIG_URL; LAutoProxyOptions.lpszAutoConfigUrl := LpProxyConfig^.lpszAutoConfigUrl; LAutoDetectProxy := True; end // *** Proxy explizit setzen, wenn wirklich keine AutoDetect aktiviert else if not LAutoDetectProxy then begin AProxy := LpProxyConfig^.lpszProxy; AProxyBypass := LpProxyConfig^.lpszProxyBypass; end; end else [... weiter wie oben ...] Als Workaround bis das von Emba mal gefixt wird, fällt mir nur ein, die System.Net.HttpClient.Win lokal ins Projekt einzubauen und die Stellen wie oben angegeben zu korrigieren. Hat hier jemand eine bessere Idee? |
![]() |
Ansicht |
![]() |
![]() |
![]() |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
![]() |
![]() |