Codeunit 1299 Web Request Helper, source in 29
Source29
src/Layers/W1/BaseApp/Modules/System/WebRequest/WebRequestHelper.Codeunit.al211 lines, Copyright (c) Microsoft Corporation. MIT
namespace System.Integration;
using System;
using System.Utilities;
codeunit 1299 "Web Request Helper"
{
trigger OnRun()
begin
end;
var
ConnectionErr: Label 'Connection to the remote service could not be established.\\';
InvalidEncodingErr: Label 'The text encoding is not specified or is not valid.';
InvalidUriErr: Label 'The URI is not valid.';
NonSecureUriErr: Label 'The URI is not secure.';
ProcessingWindowMsg: Label 'Please wait while the server is processing your request.\This may take several minutes.';
#pragma warning disable AA0470
ServiceURLTxt: Label '\\Service URL: %1.', Comment = 'Example: ServiceURL: http://www.contoso.com/';
#pragma warning restore AA0470
GlobalHttpWebResponseError: DotNet HttpWebResponse;
[TryFunction]
procedure IsValidUri(Url: Text)
var
ResultUri: DotNet Uri;
Uri: DotNet Uri;
UriKind: DotNet UriKind;
begin
if not Uri.IsWellFormedUriString(Url, UriKind.Absolute) then
if not Uri.TryCreate(Url, UriKind.Absolute, ResultUri) then
Error(InvalidUriErr);
end;
[TryFunction]
procedure IsValidUriWithoutProtocol(Url: Text)
begin
if not IsValidUri(Url) then
if not IsValidUri('http://' + Url) then
Error(InvalidUriErr);
end;
[TryFunction]
procedure IsSecureHttpUrl(Url: Text)
var
Uri: DotNet Uri;
begin
IsValidUri(Url);
Uri := Uri.Uri(Url);
if Uri.Scheme <> 'https' then
Error(NonSecureUriErr);
end;
[TryFunction]
procedure IsHttpUrl(Url: Text)
var
Uri: DotNet Uri;
begin
IsValidUri(Url);
Uri := Uri.Uri(Url);
if (Uri.Scheme <> 'http') and (Uri.Scheme <> 'https') then
Error(InvalidUriErr);
end;
[TryFunction]
[NonDebuggable]
[Scope('OnPrem')]
procedure GetWebResponse(var HttpWebRequest: DotNet HttpWebRequest; var HttpWebResponse: DotNet HttpWebResponse; var ResponseInStream: InStream; var HttpStatusCode: DotNet HttpStatusCode; var ResponseHeaders: DotNet NameValueCollection; ProgressDialogEnabled: Boolean)
var
ProcessingWindow: Dialog;
begin
if ProgressDialogEnabled then
ProcessingWindow.Open(ProcessingWindowMsg);
ClearLastError();
HttpWebResponse := HttpWebRequest.GetResponse();
HttpWebResponse.GetResponseStream().CopyTo(ResponseInStream);
HttpStatusCode := HttpWebResponse.StatusCode;
ResponseHeaders := HttpWebResponse.Headers;
if ProgressDialogEnabled then
ProcessingWindow.Close();
end;
[Scope('OnPrem')]
procedure GetWebResponseError(var WebException: DotNet WebException; var ServiceURL: Text): Text
var
DotNetExceptionHandler: Codeunit "DotNet Exception Handler";
WebExceptionStatus: DotNet WebExceptionStatus;
HttpStatusCode: DotNet HttpStatusCode;
ErrorText: Text;
begin
DotNetExceptionHandler.Collect();
if not DotNetExceptionHandler.CastToType(WebException, GetDotNetType(WebException)) then
DotNetExceptionHandler.Rethrow();
if not IsNull(WebException.Response) then
if not IsNull(WebException.Response.ResponseUri) then
ServiceURL := StrSubstNo(ServiceURLTxt, WebException.Response.ResponseUri.AbsoluteUri);
ErrorText := ConnectionErr + WebException.Message + ServiceURL;
if not WebException.Status.Equals(WebExceptionStatus.ProtocolError) then
exit(ErrorText);
if IsNull(WebException.Response) then
DotNetExceptionHandler.Rethrow();
GlobalHttpWebResponseError := WebException.Response;
if not (GlobalHttpWebResponseError.StatusCode.Equals(HttpStatusCode.Found) or
GlobalHttpWebResponseError.StatusCode.Equals(HttpStatusCode.InternalServerError))
then
exit(ErrorText);
exit('');
end;
[TryFunction]
[Scope('OnPrem')]
[NonDebuggable]
procedure GetResponseTextUsingCharset(Method: Text; Url: Text; AccessToken: SecretText; var ResponseText: Text)
begin
GetResponseTextInternal(Method, Url, AccessToken, ResponseText, false);
end;
[TryFunction]
[NonDebuggable]
[Scope('OnPrem')]
local procedure GetResponseTextInternal(Method: Text; Url: Text; AccessToken: SecretText; var ResponseText: Text; IgnoreCharSet: Boolean)
var
TempBlob: Codeunit "Temp Blob";
HttpWebRequest: DotNet HttpWebRequest;
HttpWebResponse: DotNet HttpWebResponse;
ResponseInputStream: InStream;
TextEncodingVar: TextEncoding;
ChunkText: Text;
begin
HttpWebRequest := HttpWebRequest.Create(Url);
HttpWebRequest.Method := Method;
HttpWebRequest.ContentLength := 0;
// add the access token to the authorization bearer header
HttpWebRequest.Headers().Add('Authorization', SecretStrSubstNo('Bearer %1', AccessToken).Unwrap());
HttpWebResponse := HttpWebRequest.GetResponse();
// We need to read using the right encoding, unless forced or unless no encoding can be determined
if IgnoreCharSet then
TempBlob.CreateInStream(ResponseInputStream)
else
if TryGetTextEncodingFromResponse(HttpWebResponse, TextEncodingVar) then
TempBlob.CreateInStream(ResponseInputStream, TextEncodingVar)
else
TempBlob.CreateInStream(ResponseInputStream); // Fallback to default encoding
HttpWebResponse.GetResponseStream().CopyTo(ResponseInputStream);
// the READTEXT() function apparently only reads a single line, so we must loop through the stream to get the contents of every line.
while not ResponseInputStream.EOS() do begin
ResponseInputStream.ReadText(ChunkText);
ResponseText += ChunkText;
end;
HttpWebResponse.Close(); // close connection
HttpWebResponse.Dispose(); // cleanup of IDisposable
end;
[TryFunction]
local procedure TryGetTextEncodingFromResponse(HttpWebResponse: DotNet HttpWebResponse; var EncodingToUse: TextEncoding)
var
HttpContentTypeHeader: Text;
HttpContentType: DotNet HttpContentType;
begin
// Both the header name and the content are case insensitive; returns empty string if the header does not exist
HttpContentTypeHeader := HttpWebResponse.GetResponseHeader('Content-Type').ToLowerInvariant();
HttpContentType := HttpContentType.ContentType(HttpContentTypeHeader);
if IsNull(HttpContentType.CharSet()) then
Error(InvalidEncodingErr);
if HttpContentType.CharSet() = '' then
Error(InvalidEncodingErr);
case HttpContentType.CharSet() of
'utf-8':
EncodingToUse := TextEncoding::UTF8;
else
Error(InvalidEncodingErr);
end;
end;
procedure GetHostNameFromUrl(Url: Text): Text
var
Uri: DotNet Uri;
begin
IsValidUri(Url);
Uri := Uri.Uri(Url);
exit(Uri.Host);
end;
procedure IsFailureStatusCode(TextStatusCode: Text): Boolean
var
IntStatusCode: Integer;
begin
if not Evaluate(IntStatusCode, TextStatusCode) then
exit(false);
exit(IntStatusCode > 399);
end;
}