Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 48 additions & 27 deletions Source/Alcinoe.HTTP.Client.WinINet.pas
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ TALWinInetHTTPClient = class(TALHTTPClient)
FInetConnect: HINTERNET;
FOnStatus: TAlWinInetHTTPClientStatusEvent;
FIgnoreSecurityErrors: Boolean;
FAllowHttp2Protocol: Boolean;
procedure SetAccessType(const Value: TALWinInetHttpInternetOpenAccessType);
procedure SetInternetOptions(const Value: TAlWininetHTTPClientInternetOptionSet);
procedure SetOnStatus(const Value: TAlWinInetHTTPClientStatusEvent);
Expand Down Expand Up @@ -193,6 +194,7 @@ TALWinInetHTTPClient = class(TALHTTPClient)
property InternetOptions: TAlWininetHTTPClientInternetOptionSet read FInternetOptions write SetInternetOptions default [wHttpIo_Keep_connection];
property OnStatus: TAlWinInetHTTPClientStatusEvent read FOnStatus write SetOnStatus;
property IgnoreSecurityErrors: Boolean read FIgnoreSecurityErrors write FIgnoreSecurityErrors;
property AllowHttp2Protocol: Boolean read FAllowHttp2Protocol write FAllowHttp2Protocol;
end;

implementation
Expand Down Expand Up @@ -246,6 +248,7 @@ constructor TALWinInetHTTPClient.Create;
FInternetOptions := [wHttpIo_Keep_connection];
RequestHeader.UserAgent := 'Mozilla/3.0 (compatible; TALWinInetHTTPClient)';
FIgnoreSecurityErrors := False;
FAllowHttp2Protocol := False;
end;

{**************************************}
Expand Down Expand Up @@ -378,17 +381,36 @@ procedure TALWinInetHTTPClient.Connect;
if whttpIo_Offline in InternetOptions then Result := result or INTERNET_FLAG_OFFLINE;
end;

Function InternalGetInternetSecurityFlags: DWord;
Begin
Result := 0;
if FURLScheme = INTERNET_SCHEME_HTTPS then begin
if FIgnoreSecurityErrors then begin
Result := Result or SECURITY_SET_MASK;
end else begin
if whttpIo_IGNORE_CERT_CN_INVALID in InternetOptions then
Result := Result or SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
if whttpIo_IGNORE_CERT_DATE_INVALID in InternetOptions then
Result := Result or SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
end;
end;
end;

const
AccessTypeArr: Array[TALWinInetHttpInternetOpenAccessType] of DWord = (INTERNET_OPEN_TYPE_DIRECT,
INTERNET_OPEN_TYPE_PRECONFIG,
INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY,
INTERNET_OPEN_TYPE_PROXY);
const
HTTP_PROTOCOL_FLAG_HTTP2 = 2;
INTERNET_OPTION_ENABLE_HTTP_PROTOCOL = 148;

var
LSetStatusCallbackResult: PFNInternetStatusCallback;
ProxyStr: AnsiString;
ProxyPtr: PAnsiChar;

LProxyStr: AnsiString;
LProxyPtr: PAnsiChar;
LUserAgent: AnsiString;
LOption: DWORD;
begin
{ Yes, but what if we're connected to a different Host/Port?? }
{ So take advantage of a cached handle, we'll assume that
Expand All @@ -399,20 +421,22 @@ procedure TALWinInetHTTPClient.Connect;
{ Also, could switch to new API introduced in IE4/Preview2}
if InternetAttemptConnect(0) <> ERROR_SUCCESS then System.SysUtils.Abort;

ProxyStr := InternalGetProxyServerName;
if ProxyStr <> '' then begin
ProxyPtr := PAnsiChar(ProxyStr);
LProxyStr := InternalGetProxyServerName;
if LProxyStr <> '' then begin
LProxyPtr := PAnsiChar(LProxyStr);
end else begin
ProxyPtr := nil;
LProxyPtr := nil;
end;

LUserAgent := RequestHeader.UserAgent;

{init FInetRoot}
FInetRoot := InternetOpenA(
PAnsiChar(RequestHeader.UserAgent),
PAnsiChar(LUserAgent),
AccessTypeArr[FAccessType],
ProxyPtr,
LProxyPtr,
InternalGetProxyBypass,
InternalGetInternetOpenFlags);
InternalGetInternetOpenFlags or InternalGetInternetSecurityFlags);
CheckError(not Assigned(FInetRoot));

try
Expand All @@ -423,6 +447,13 @@ procedure TALWinInetHTTPClient.Connect;
CheckError(LSetStatusCallbackResult = pointer(INTERNET_INVALID_STATUS_CALLBACK));
end;

{Enable HTTP/2 protocol (for Windows 10 and later)}
if FAllowHttp2Protocol and (FURLScheme = INTERNET_SCHEME_HTTPS) then begin
LOption := HTTP_PROTOCOL_FLAG_HTTP2;
// ignore any errors, because this protocol is optional
InternetSetOptionA(FInetRoot, INTERNET_OPTION_ENABLE_HTTP_PROTOCOL, Pointer(@LOption), SizeOf(LOption));
end;

{init FInetConnect}
FInetConnect := InternetConnectA(
FInetRoot,
Expand Down Expand Up @@ -466,8 +497,6 @@ function TALWinInetHTTPClient.Send(
Result := 0;
if whttpIo_CACHE_IF_NET_FAIL in InternetOptions then Result := result or INTERNET_FLAG_CACHE_IF_NET_FAIL;
if whttpIo_HYPERLINK in InternetOptions then Result := result or INTERNET_FLAG_HYPERLINK;
if whttpIo_IGNORE_CERT_CN_INVALID in InternetOptions then Result := result or INTERNET_FLAG_IGNORE_CERT_CN_INVALID;
if whttpIo_IGNORE_CERT_DATE_INVALID in InternetOptions then Result := result or INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
if whttpIo_IGNORE_REDIRECT_TO_HTTP in InternetOptions then Result := result or INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP;
if whttpIo_IGNORE_REDIRECT_TO_HTTPS in InternetOptions then Result := result or INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS;
if whttpIo_KEEP_CONNECTION in InternetOptions then Result := result or INTERNET_FLAG_KEEP_CONNECTION;
Expand Down Expand Up @@ -507,11 +536,11 @@ function TALWinInetHTTPClient.Send(
end;

var LNumberOfBytesWritten: DWord;
LDwFlags: DWORD;
LBuffLen: Cardinal;
LBuffSize, LLen: cardinal;
LINBuffer: INTERNET_BUFFERSA;
LBuffer: TMemoryStream;
LAccept: AnsiString;
LReferrer: AnsiString;
LAcceptTypes: array of PAnsiChar;
LHeader: AnsiString;
LOption: DWord;
Expand All @@ -521,32 +550,24 @@ function TALWinInetHTTPClient.Send(
{ Connect }
Connect;

LAccept := RequestHeader.Accept;
LReferrer := RequestHeader.Referer;

SetLength(LAcceptTypes, 2);
LAcceptTypes[0] := PAnsiChar(RequestHeader.Accept);
LAcceptTypes[0] := PAnsiChar(LAccept);
LAcceptTypes[1] := nil;

Result := HttpOpenRequestA(
FInetConnect,
InternalGetHttpOpenRequestVerb,
PAnsiChar(FURLPath),
InternalGetHttpProtocolVersion,
PAnsiChar(requestHeader.Referer),
PAnsiChar(LReferrer),
Pointer(LAcceptTypes),
InternalGetHttpOpenRequestFlags,
DWORD_PTR(Self));
CheckError(not Assigned(Result));
try

if FIgnoreSecurityErrors and (FURLScheme = INTERNET_SCHEME_HTTPS) then begin
LBuffLen := SizeOf(LDwFlags);
CheckError(not InternetQueryOptionA(Result, INTERNET_OPTION_SECURITY_FLAGS, Pointer(@LDwFlags), LBuffLen));
LDwFlags := LDwFlags or
SECURITY_FLAG_IGNORE_REVOCATION or
SECURITY_FLAG_IGNORE_UNKNOWN_CA or
SECURITY_FLAG_IGNORE_WRONG_USAGE;
CheckError(not InternetSetOptionA(Result, INTERNET_OPTION_SECURITY_FLAGS, Pointer(@LDwFlags), SizeOf(LDwFlags)));
end;

{ Timeouts }
if ConnectTimeout > 0 then begin
LOption := ConnectTimeout;
Expand Down