From 53d521e6971127cf90e01ccff5e4c5b79637e44b Mon Sep 17 00:00:00 2001 From: claudiamurialdo Date: Wed, 1 Oct 2025 20:37:21 -0300 Subject: [PATCH 1/5] Unify file download logic to always set a configurable User-Agent The User-Agent is now consistently applied using the GX_HTTPCLIENT_USER_AGENT environment variable or HTTPCLIENT_USER_AGENT in appsettings.json Affects the following functionalities: Adding an image to a PDF ImageAPI when handling images from a URL Inserting an image from url in the database (GetBinary in GxDataRecord) --- .../GxPdfReportsCS/PDFReportPDFPig.cs | 20 ++++---- .../GxClasses/Core/GXUtilsCommon.cs | 46 +++++++++---------- .../GxClasses/Core/gxconfig.cs | 17 +++++++ .../GxClasses/Domain/GxHttpClient.cs | 29 ++++++++---- .../GxClasses/Helpers/HttpHelper.cs | 14 +++++- 5 files changed, 80 insertions(+), 46 deletions(-) diff --git a/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportPDFPig.cs b/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportPDFPig.cs index 9a6f45587..57f1e5d73 100644 --- a/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportPDFPig.cs +++ b/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportPDFPig.cs @@ -16,7 +16,6 @@ using Font = System.Drawing.Font; #endif using System.IO; -using System.Net.Http; using System.Text; using GeneXus; using UglyToad.PdfPig.Core; @@ -27,6 +26,8 @@ using static UglyToad.PdfPig.Writer.PdfPageBuilder; using PageSize = UglyToad.PdfPig.Content.PageSize; using PdfRectangle = UglyToad.PdfPig.Core.PdfRectangle; +using System.Net; +using GeneXus.Http; namespace GeneXus.Printer { @@ -272,17 +273,14 @@ public override void GxDrawBitMap(string bitmap, int left, int top, int right, i private AddedImage AddImageFromURL(string url, PdfRectangle position) { AddedImage image = null; - using (HttpClient httpClient = new HttpClient()) + byte[] imageBytes = HttpHelper.DownloadFile(url, out HttpStatusCode statusCode); + try { - byte[] imageBytes = httpClient.GetByteArrayAsync(url).Result; - try - { - image = pageBuilder.AddJpeg(imageBytes, position); - } - catch (Exception) - { - pageBuilder.AddPng(imageBytes, position); - } + image = pageBuilder.AddJpeg(imageBytes, position); + } + catch (Exception) + { + pageBuilder.AddPng(imageBytes, position); } if (image == null) { diff --git a/dotnet/src/dotnetframework/GxClasses/Core/GXUtilsCommon.cs b/dotnet/src/dotnetframework/GxClasses/Core/GXUtilsCommon.cs index 9ce09894b..98a888608 100644 --- a/dotnet/src/dotnetframework/GxClasses/Core/GXUtilsCommon.cs +++ b/dotnet/src/dotnetframework/GxClasses/Core/GXUtilsCommon.cs @@ -15,8 +15,8 @@ #if NETCORE using Microsoft.AspNetCore.Http; using GxClasses.Helpers; -using System.Net; #endif +using System.Net; using NodaTime; using NUglify; using NUglify.Html; @@ -38,6 +38,11 @@ using GeneXus.Http; using System.Security; using System.Net.Http.Headers; +using System.Security.Policy; +using GeneXus.Http.Client; + + + #if NETCORE using Image = GeneXus.Drawing.Image; using GeneXus.Drawing; @@ -51,6 +56,7 @@ #endif using System.Net.Http; + namespace GeneXus.Utils { public class GxDefaultProps @@ -5885,21 +5891,18 @@ private static Bitmap BitmapCreateFromStream(string filePathOrUrl) Uri uri; if (Uri.TryCreate(filePathOrUrl, UriKind.Absolute, out uri) && (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)) { - using (HttpClient httpClient = new HttpClient()) + try { - try + byte[] data = HttpHelper.DownloadFile(uri.AbsoluteUri, out HttpStatusCode statusCode); + using (MemoryStream mem = new MemoryStream(data)) { - byte[] data = httpClient.GetByteArrayAsync(uri).Result; - using (MemoryStream mem = new MemoryStream(data)) - { - return new Bitmap(mem); - } - } - catch - { - return null; + return new Bitmap(mem); } } + catch + { + return null; + } } else { @@ -5917,21 +5920,18 @@ private static Image ImageCreateFromStream(string filePathOrUrl) Uri uri; if (Uri.TryCreate(filePathOrUrl, UriKind.Absolute, out uri) && (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)) { - using (HttpClient httpClient = new HttpClient()) + try { - try - { - byte[] data = httpClient.GetByteArrayAsync(uri).Result; - using (MemoryStream mem = new MemoryStream(data)) - { - return Image.FromStream(mem); - } - } - catch + byte[] data = HttpHelper.DownloadFile(uri.AbsoluteUri, out HttpStatusCode statusCode); + using (MemoryStream mem = new MemoryStream(data)) { - return null; + return Image.FromStream(mem); } } + catch + { + return null; + } } else { diff --git a/dotnet/src/dotnetframework/GxClasses/Core/gxconfig.cs b/dotnet/src/dotnetframework/GxClasses/Core/gxconfig.cs index 34406657f..9a9df9421 100644 --- a/dotnet/src/dotnetframework/GxClasses/Core/gxconfig.cs +++ b/dotnet/src/dotnetframework/GxClasses/Core/gxconfig.cs @@ -860,6 +860,7 @@ public class Preferences public static string DefaultRewriteFile = "rewrite.config"; const string USE_NAMED_PARAMETERS = "UseNamedParameters"; const string REST_DATES_WITH_MILLIS = "REST_DATES_WITH_MILLIS"; + const string HTTPCLIENT_USER_AGENT = "HTTPCLIENT_USER_AGENT"; internal const string YES = "1"; internal const string NO = "0"; static string defaultDatastore; @@ -875,6 +876,22 @@ internal static string AppMainNamespace return nameSpace; } } + internal static string HttpClientUserAgent + { + get + { + if (Config.GetValueOrEnvironmentVarOf(HTTPCLIENT_USER_AGENT, out string userAgent)) + return userAgent; + else + { + if (Config.GetValueOf("VER_STAMP", out string version)) + return $"{AppMainNamespace}/{version}"; + else + return $"{AppMainNamespace}"; + } + } + } + internal static bool IsBeforeConnectEventConfigured() { return (Config.GetValueOf("EVENT_BEFORE_CONNECT", out string evtProcName) && !string.IsNullOrEmpty(evtProcName)); diff --git a/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs b/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs index 62e3de2c0..15088f2c0 100644 --- a/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs +++ b/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs @@ -158,40 +158,49 @@ private async Task ReceiveDataAsync() } private const int POOLED_CONNECTION_LIFETIME_MINUTES = 2; + internal static ConcurrentDictionary _httpClientInstances = new ConcurrentDictionary(); + internal static HttpClient GetHttpClientInstance(Uri uri, out bool disposableInstance) + { + return GetHttpClientInstance(uri, 0, null, null, null, null, string.Empty, 0, out disposableInstance); + } private static HttpClient GetHttpClientInstance(Uri URI, int timeout, ArrayList authCollection, ArrayList authProxyCollection, X509Certificate2Collection certificateCollection, List fileCertificateCollection, string proxyHost, int proxyPort, out bool disposableInstance) { + HttpClient client; if (CacheableInstance(authCollection, authProxyCollection)) { - HttpClient value; disposableInstance = false; string key = HttpClientInstanceIdentifier(proxyHost, proxyPort, fileCertificateCollection, timeout); - if (_httpClientInstances.TryGetValue(key, out value)) + if (_httpClientInstances.TryGetValue(key, out client)) { GXLogging.Debug(log, $"Getting httpClient cached instance"); - return value; + return client; } else { lock (syncRootHttpInstance) { - if (_httpClientInstances.TryGetValue(key, out value)) + if (_httpClientInstances.TryGetValue(key, out client)) { GXLogging.Debug(log, $"Getting httpClient cached instance"); - return value; + return client; + } + client = new HttpClient(GetHandler(URI, authCollection, authProxyCollection, certificateCollection, proxyHost, proxyPort)); + if (timeout != 0) + { + client.Timeout = TimeSpan.FromMilliseconds(timeout); } - value = new HttpClient(GetHandler(URI, authCollection, authProxyCollection, certificateCollection, proxyHost, proxyPort)); - value.Timeout = TimeSpan.FromMilliseconds(timeout); - _httpClientInstances.TryAdd(key, value); - return value; + _httpClientInstances.TryAdd(key, client); } } } else { disposableInstance = true; - return new HttpClient(GetHandler(URI, authCollection, authProxyCollection, certificateCollection, proxyHost, proxyPort)); + client = new HttpClient(GetHandler(URI, authCollection, authProxyCollection, certificateCollection, proxyHost, proxyPort)); } + client.DefaultRequestHeaders.UserAgent.ParseAdd(Preferences.HttpClientUserAgent); + return client; } private static string HttpClientInstanceIdentifier(string proxyHost, int proxyPort, List fileCertificateCollection, int timeout) diff --git a/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs b/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs index 4554f8415..f1e580a8b 100644 --- a/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs +++ b/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs @@ -28,6 +28,8 @@ using System.Net.Http; using System.Globalization; using System.Linq; +using GeneXus.Http.Client; +using System.Net.Http.Headers; namespace GeneXus.Http { @@ -55,6 +57,7 @@ public class HttpHeader internal static string X_CSRF_TOKEN_COOKIE = "XSRF-TOKEN"; internal static string AUTHORIZATION = "Authorization"; internal static string CONTENT_TYPE = "Content-Type"; + internal static string USER_AGENT = "User-Agent"; } internal class HttpHeaderValue { @@ -530,9 +533,10 @@ public static string RequestPhysicalApplicationPath(HttpContext context = null) public static byte[] DownloadFile(string url, out HttpStatusCode statusCode) { byte[] buffer = Array.Empty(); - using (var client = new HttpClient()) + HttpClient httpClient = GxHttpClient.GetHttpClientInstance(new Uri(url), out bool disposableInstance); + try { - using (HttpResponseMessage response = client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead).Result) + using (HttpResponseMessage response = httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead).Result) { if (response.IsSuccessStatusCode) { @@ -548,6 +552,11 @@ public static byte[] DownloadFile(string url, out HttpStatusCode statusCode) } } } + finally + { + if (disposableInstance) + httpClient.Dispose(); + } return buffer; } @@ -558,6 +567,7 @@ internal static byte[] DownloadFile(string fileName, out HttpStatusCode statusCo try { WebClient Client = new WebClient(); + Client.Headers.Add(HttpHeader.USER_AGENT, Preferences.HttpClientUserAgent); binary = Client.DownloadData(fileName); statusCode = HttpStatusCode.OK; } From 69a161f7b813b000f8e06e6ac3110c10f0ad6fb2 Mon Sep 17 00:00:00 2001 From: claudiamurialdo Date: Thu, 2 Oct 2025 09:28:47 -0300 Subject: [PATCH 2/5] Skip adding User-Agent by default for compatibility --- dotnet/src/dotnetframework/GxClasses/Core/gxconfig.cs | 7 +------ .../src/dotnetframework/GxClasses/Domain/GxHttpClient.cs | 3 ++- dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs | 3 ++- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/dotnet/src/dotnetframework/GxClasses/Core/gxconfig.cs b/dotnet/src/dotnetframework/GxClasses/Core/gxconfig.cs index 9a9df9421..982c5d23f 100644 --- a/dotnet/src/dotnetframework/GxClasses/Core/gxconfig.cs +++ b/dotnet/src/dotnetframework/GxClasses/Core/gxconfig.cs @@ -883,12 +883,7 @@ internal static string HttpClientUserAgent if (Config.GetValueOrEnvironmentVarOf(HTTPCLIENT_USER_AGENT, out string userAgent)) return userAgent; else - { - if (Config.GetValueOf("VER_STAMP", out string version)) - return $"{AppMainNamespace}/{version}"; - else - return $"{AppMainNamespace}"; - } + return string.Empty; } } diff --git a/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs b/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs index 15088f2c0..234dfaa3a 100644 --- a/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs +++ b/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs @@ -199,7 +199,8 @@ private static HttpClient GetHttpClientInstance(Uri URI, int timeout, ArrayList disposableInstance = true; client = new HttpClient(GetHandler(URI, authCollection, authProxyCollection, certificateCollection, proxyHost, proxyPort)); } - client.DefaultRequestHeaders.UserAgent.ParseAdd(Preferences.HttpClientUserAgent); + if (!string.IsNullOrEmpty(Preferences.HttpClientUserAgent)) + client.DefaultRequestHeaders.UserAgent.ParseAdd(Preferences.HttpClientUserAgent); return client; } diff --git a/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs b/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs index f1e580a8b..cb0270676 100644 --- a/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs +++ b/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs @@ -567,7 +567,8 @@ internal static byte[] DownloadFile(string fileName, out HttpStatusCode statusCo try { WebClient Client = new WebClient(); - Client.Headers.Add(HttpHeader.USER_AGENT, Preferences.HttpClientUserAgent); + if (!string.IsNullOrEmpty(Preferences.HttpClientUserAgent)) + Client.Headers.Add(HttpHeader.USER_AGENT, Preferences.HttpClientUserAgent); binary = Client.DownloadData(fileName); statusCode = HttpStatusCode.OK; } From 03b3c1714ca0b5f638f1cfe38b021e824802a629 Mon Sep 17 00:00:00 2001 From: claudiamurialdo Date: Fri, 3 Oct 2025 22:27:37 -0300 Subject: [PATCH 3/5] Add null checks for collections in HttpClient --- .../dotnetframework/GxClasses/Domain/GxCollections.cs | 1 + .../dotnetframework/GxClasses/Domain/GxHttpClient.cs | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/dotnet/src/dotnetframework/GxClasses/Domain/GxCollections.cs b/dotnet/src/dotnetframework/GxClasses/Domain/GxCollections.cs index b1bbcb3be..d8fac1c36 100644 --- a/dotnet/src/dotnetframework/GxClasses/Domain/GxCollections.cs +++ b/dotnet/src/dotnetframework/GxClasses/Domain/GxCollections.cs @@ -2833,6 +2833,7 @@ static public object ConvertToExternal(Type to, Object i) } return o; } + internal static bool IsNullOrEmpty(IList collection) => collection == null || collection.Count == 0; } public interface IGxCollectionConverter { diff --git a/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs b/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs index 234dfaa3a..d52120486 100644 --- a/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs +++ b/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs @@ -207,11 +207,11 @@ private static HttpClient GetHttpClientInstance(Uri URI, int timeout, ArrayList private static string HttpClientInstanceIdentifier(string proxyHost, int proxyPort, List fileCertificateCollection, int timeout) { bool defaultSslOptions = ServicePointManager.ServerCertificateValidationCallback == null; - if (string.IsNullOrEmpty(proxyHost) && fileCertificateCollection.Count==0 && timeout== DEFAULT_TIMEOUT && defaultSslOptions) + if (string.IsNullOrEmpty(proxyHost) && CollectionUtils.IsNullOrEmpty(fileCertificateCollection) && timeout== DEFAULT_TIMEOUT && defaultSslOptions) { return string.Empty; } - else if (fileCertificateCollection.Count==0) + else if (CollectionUtils.IsNullOrEmpty(fileCertificateCollection)) { return $"{proxyHost}:{proxyPort}::{timeout}:{defaultSslOptions}"; } @@ -223,7 +223,7 @@ private static string HttpClientInstanceIdentifier(string proxyHost, int proxyPo private static bool CacheableInstance(ArrayList authCollection, ArrayList authProxyCollection) { - return authCollection.Count == 0 && authProxyCollection.Count == 0 && Preferences.SingletonHttpClient(); + return CollectionUtils.IsNullOrEmpty(authCollection) && CollectionUtils.IsNullOrEmpty(authProxyCollection) && Preferences.SingletonHttpClient(); } private static SocketsHttpHandler GetHandler(Uri URI, ArrayList authCollection, ArrayList authProxyCollection, X509Certificate2Collection certificateCollection, string proxyHost, int proxyPort) { @@ -249,7 +249,7 @@ private static SocketsHttpHandler GetHandler(Uri URI, ArrayList authCollection, { handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; } - if (certificateCollection.Count > 0) + if (!CollectionUtils.IsNullOrEmpty(certificateCollection)) { if (handler.SslOptions.ClientCertificates == null) { @@ -1600,6 +1600,8 @@ static ICredentials getCredentialCache(Uri URI, ArrayList authenticationCollecti string sScheme; GxAuthScheme auth; CredentialCache cc = null; + if (CollectionUtils.IsNullOrEmpty(authenticationCollection)) + return null; for (int i = 0; i < authenticationCollection.Count; i++) { From 23931cbf657e3d7af6304addbfe1c043118eae19 Mon Sep 17 00:00:00 2001 From: claudiamurialdo Date: Fri, 10 Oct 2025 12:30:09 -0300 Subject: [PATCH 4/5] Rename constant HTTPCLIENT_USER_AGENT to UserAgentHeader for consistency with the property name --- dotnet/src/dotnetframework/GxClasses/Core/gxconfig.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dotnet/src/dotnetframework/GxClasses/Core/gxconfig.cs b/dotnet/src/dotnetframework/GxClasses/Core/gxconfig.cs index 982c5d23f..3ccf5b845 100644 --- a/dotnet/src/dotnetframework/GxClasses/Core/gxconfig.cs +++ b/dotnet/src/dotnetframework/GxClasses/Core/gxconfig.cs @@ -860,7 +860,7 @@ public class Preferences public static string DefaultRewriteFile = "rewrite.config"; const string USE_NAMED_PARAMETERS = "UseNamedParameters"; const string REST_DATES_WITH_MILLIS = "REST_DATES_WITH_MILLIS"; - const string HTTPCLIENT_USER_AGENT = "HTTPCLIENT_USER_AGENT"; + const string UserAgentHeader = "UserAgentHeader"; internal const string YES = "1"; internal const string NO = "0"; static string defaultDatastore; @@ -880,7 +880,7 @@ internal static string HttpClientUserAgent { get { - if (Config.GetValueOrEnvironmentVarOf(HTTPCLIENT_USER_AGENT, out string userAgent)) + if (Config.GetValueOrEnvironmentVarOf(UserAgentHeader, out string userAgent)) return userAgent; else return string.Empty; From b1adbd21b0363002ebb43575b63bf6b58c4d5454 Mon Sep 17 00:00:00 2001 From: claudiamurialdo Date: Mon, 13 Oct 2025 16:10:43 -0300 Subject: [PATCH 5/5] Make reports respect the provided User-Agent header when adding external images to PDFs. --- .../GxPdfReportsCS/PDFReportItext8.cs | 20 +++++++++---- .../GxPdfReportsCS/PDFReportPDFPig.cs | 25 ++++++++++++----- .../GxClasses/Helpers/HttpHelper.cs | 2 +- .../GxPdfReportsCS/PDFReportItext4.cs | 28 ++++++++++++------- 4 files changed, 51 insertions(+), 24 deletions(-) diff --git a/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportItext8.cs b/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportItext8.cs index 0670eb172..8222dd9e4 100644 --- a/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportItext8.cs +++ b/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportItext8.cs @@ -5,6 +5,8 @@ using System.IO; using System.Text; using GeneXus; +using GeneXus.Http; +using GeneXus.Utils; using iText.Barcodes; using iText.Html2pdf; using iText.Html2pdf.Resolver.Font; @@ -481,16 +483,22 @@ public override void GxDrawBitMap(String bitmap, int left, int top, int right, i { if (!Path.IsPathRooted(bitmap)) { - - image = new Image(ImageDataFactory.Create(defaultRelativePrepend + bitmap)); - if (image == null) + if (PathUtil.IsAbsoluteUrl(bitmap)) { - bitmap = webAppDir + bitmap; - image = new Image(ImageDataFactory.Create(bitmap)); + image = new Image(ImageDataFactory.Create(HttpHelper.DownloadFile(bitmap, out _))); } else { - bitmap = defaultRelativePrepend + bitmap; + image = new Image(ImageDataFactory.Create(defaultRelativePrepend + bitmap)); + if (image == null) + { + bitmap = webAppDir + bitmap; + image = new Image(ImageDataFactory.Create(bitmap)); + } + else + { + bitmap = defaultRelativePrepend + bitmap; + } } } else diff --git a/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportPDFPig.cs b/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportPDFPig.cs index 57f1e5d73..6fd6d90c1 100644 --- a/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportPDFPig.cs +++ b/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportPDFPig.cs @@ -28,6 +28,7 @@ using PdfRectangle = UglyToad.PdfPig.Core.PdfRectangle; using System.Net; using GeneXus.Http; +using GeneXus.Utils; namespace GeneXus.Printer { @@ -228,24 +229,34 @@ public override void GxDrawBitMap(string bitmap, int left, int top, int right, i { try { + byte[] imageBytes; if (!Path.IsPathRooted(bitmap)) { - - image = imageType == "jpeg" ? pageBuilder.AddJpeg(File.ReadAllBytes(defaultRelativePrepend + bitmap), position) : pageBuilder.AddPng(File.ReadAllBytes(defaultRelativePrepend + bitmap), position); - if (image == null) + if (PathUtil.IsAbsoluteUrl(bitmap)) { - bitmap = webAppDir + bitmap; - image = imageType == "jpeg" ? pageBuilder.AddJpeg(File.ReadAllBytes(bitmap), position) : pageBuilder.AddPng(File.ReadAllBytes(bitmap), position); + imageBytes = HttpHelper.DownloadFile(bitmap, out _); } else { - bitmap = defaultRelativePrepend + bitmap; + string bitmapPath = Path.Combine(defaultRelativePrepend, bitmap); + if (File.Exists(bitmapPath)) + { + imageBytes = File.ReadAllBytes(bitmapPath); + bitmap = bitmapPath; + } + else + { + bitmapPath = Path.Combine(webAppDir, bitmap); + imageBytes = File.ReadAllBytes(bitmapPath); + bitmap = bitmapPath; + } } } else { - image = imageType == "jpeg" ? pageBuilder.AddJpeg(File.ReadAllBytes(bitmap), position) : pageBuilder.AddPng(File.ReadAllBytes(bitmap), position); + imageBytes = File.ReadAllBytes(bitmap); } + image = imageType == "jpeg" ? pageBuilder.AddJpeg(imageBytes, position) : pageBuilder.AddPng(imageBytes, position); } catch (Exception) { diff --git a/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs b/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs index cb0270676..dbeabfce2 100644 --- a/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs +++ b/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs @@ -561,7 +561,7 @@ public static byte[] DownloadFile(string url, out HttpStatusCode statusCode) } #else - internal static byte[] DownloadFile(string fileName, out HttpStatusCode statusCode) + public static byte[] DownloadFile(string fileName, out HttpStatusCode statusCode) { byte[] binary = Array.Empty(); try diff --git a/dotnet/src/dotnetframework/GxPdfReportsCS/PDFReportItext4.cs b/dotnet/src/dotnetframework/GxPdfReportsCS/PDFReportItext4.cs index 033f4eae3..4e4e71842 100644 --- a/dotnet/src/dotnetframework/GxPdfReportsCS/PDFReportItext4.cs +++ b/dotnet/src/dotnetframework/GxPdfReportsCS/PDFReportItext4.cs @@ -6,7 +6,9 @@ using System.Reflection; using GeneXus; using GeneXus.Configuration; +using GeneXus.Http; using GeneXus.Metadata; +using GeneXus.Utils; using iTextSharp.text; using iTextSharp.text.html.simpleparser; using iTextSharp.text.pdf; @@ -417,8 +419,8 @@ public override void GxDrawBitMap(String bitmap, int left, int top, int right, i EnsureDocumentOpen(); try { - iTextSharp.text.Image image; - iTextSharp.text.Image imageRef; + Image image; + Image imageRef; if (documentImages != null && documentImages.TryGetValue(bitmap, out imageRef)) { image = imageRef; @@ -429,24 +431,30 @@ public override void GxDrawBitMap(String bitmap, int left, int top, int right, i { if (!Path.IsPathRooted(bitmap)) { - - image = iTextSharp.text.Image.GetInstance(defaultRelativePrepend + bitmap); - if (image == null) + if (PathUtil.IsAbsoluteUrl(bitmap)) { - bitmap = webAppDir + bitmap; - image = iTextSharp.text.Image.GetInstance(bitmap); + image = Image.GetInstance(HttpHelper.DownloadFile(bitmap, out _)); } else { - bitmap = defaultRelativePrepend + bitmap; + image = Image.GetInstance(defaultRelativePrepend + bitmap); + if (image == null) + { + bitmap = webAppDir + bitmap; + image = Image.GetInstance(bitmap); + } + else + { + bitmap = defaultRelativePrepend + bitmap; + } } } else { - image = iTextSharp.text.Image.GetInstance(bitmap); + image = Image.GetInstance(bitmap); } } - catch (Exception)//absolute url + catch (Exception) { Uri uri = new Uri(bitmap); image = Image.GetInstance(uri);