Skip to content
Merged
Show file tree
Hide file tree
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
30 changes: 10 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -529,37 +529,27 @@ public async Task<Stream> FastConversion()
}
```

### Watermark & Rotation
*Add text watermarks and rotate PDF pages — available on all request types:*
### Wait For Selector & Emulated Media Features
*Wait for a DOM element and emulate CSS media features like dark mode:*

```csharp
public async Task<Stream> CreateWatermarkedPdf()
public async Task<Stream> CreateWithChromiumFeatures()
{
var builder = new HtmlRequestBuilder()
.AddDocument(doc => doc.SetBody("<html><body><h1>Report</h1></body></html>"))
.SetWatermarkOptions(w => w.SetTextWatermark("DRAFT", "1-3"))
.SetRotationOptions(r => r.SetAngle(90).SetPages("2"))
.AddDocument(doc => doc.SetBody("<html><body><div id='app'>Ready</div></body></html>"))
.SetConversionBehaviors(b => b
.SetWaitForSelector("#app")
.AddEmulatedMediaFeature("prefers-color-scheme", "dark")
.SetFailOnHttpStatusCodes(499, 599)
.FailOnResourceLoadingFailed()
.AddIgnoreResourceHttpStatusDomains("cdn.example.com"))
.WithPageProperties(pp => pp.UseChromeDefaults());

var request = builder.Build();
return await _sharpClient.HtmlToPdfAsync(request);
}
```

### Split PDFs
*Split generated PDFs into chunks or extract specific pages:*

```csharp
public async Task<Stream> SplitPdf()
{
var builder = new HtmlRequestBuilder()
.AddDocument(doc => doc.SetBody("<html><body>Multi-page content</body></html>"))
.SetSplitOptions(s => s.SplitByPages("1-3,5", unify: true));

var request = builder.Build();
return await _sharpClient.HtmlToPdfAsync(request);
}
```

### Custom Page Properties
*Fine-tune page dimensions and properties:*
Expand Down
2 changes: 2 additions & 0 deletions examples/ChromiumFeatures/ChromiumFeatures.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<Project Sdk="Microsoft.NET.Sdk">
</Project>
81 changes: 81 additions & 0 deletions examples/ChromiumFeatures/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using Gotenberg.Sharp.API.Client;
using Gotenberg.Sharp.API.Client.Domain.Builders;
using Gotenberg.Sharp.API.Client.Domain.Settings;
using Gotenberg.Sharp.API.Client.Infrastructure.Pipeline;

using Microsoft.Extensions.Configuration;

var config = new ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile("appsettings.json")
.Build();

var options = new GotenbergSharpClientOptions();
config.GetSection(nameof(GotenbergSharpClient)).Bind(options);

var destinationDirectory = args.Length > 0 ? args[0] : Path.Combine(Directory.GetCurrentDirectory(), "output");
Directory.CreateDirectory(destinationDirectory);

var path = await CreateWithChromiumFeatures(destinationDirectory, options);
Console.WriteLine($"PDF created: {path}");

static async Task<string> CreateWithChromiumFeatures(string destinationDirectory, GotenbergSharpClientOptions options)
{
var handler = new HttpClientHandler();
HttpMessageHandler effectiveHandler = handler;
if (!string.IsNullOrWhiteSpace(options.BasicAuthUsername) && !string.IsNullOrWhiteSpace(options.BasicAuthPassword))
effectiveHandler = new BasicAuthHandler(options.BasicAuthUsername, options.BasicAuthPassword) { InnerHandler = handler };

using var httpClient = new HttpClient(effectiveHandler, disposeHandler: true)
{
BaseAddress = options.ServiceUrl,
Timeout = options.TimeOut
};

var sharpClient = new GotenbergSharpClient(httpClient);

// Demonstrates waitForSelector, emulated media features, and error handling options
var builder = new HtmlRequestBuilder()
.AddDocument(doc => doc.SetBody(@"
<html>
<head>
<style>
@media (prefers-color-scheme: dark) {
body { background: #1a1a2e; color: #eee; }
}
</style>
</head>
<body>
<div id='content'>
<h1>Chromium Feature Demo</h1>
<p>This PDF was generated with dark mode emulation, waitForSelector,
and strict error handling.</p>
</div>
</body>
</html>"))
.SetConversionBehaviors(b => b
// Wait for the #content element before converting
.SetWaitForSelector("#content")
// Emulate dark mode
.AddEmulatedMediaFeature("prefers-color-scheme", "dark")
// Fail if the main page returns 4xx or 5xx
.SetFailOnHttpStatusCodes(499, 599)
// Fail if any resource fails to load
.FailOnResourceLoadingFailed()
// Fail on any console exceptions
.FailOnConsoleExceptions()
// Ignore CDN domains for status code checks
.AddIgnoreResourceHttpStatusDomains("cdn.example.com")
)
.WithPageProperties(pp => pp.UseChromeDefaults());

var request = builder.Build();
var response = await sharpClient.HtmlToPdfAsync(request);

var resultPath = Path.Combine(destinationDirectory, $"ChromiumFeatures-{DateTime.Now:yyyyMMddHHmmss}.pdf");

await using var destinationStream = File.Create(resultPath);
await response.CopyToAsync(destinationStream, CancellationToken.None);

return resultPath;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

using Gotenberg.Sharp.API.Client.Domain.ValueObjects;

using Newtonsoft.Json.Linq;

namespace Gotenberg.Sharp.API.Client.Domain.Builders.Faceted;
Expand Down Expand Up @@ -174,6 +176,171 @@ public HtmlConversionBehaviorBuilder SkipNetworkIdleEvent()
return this;
}

/// <summary>
/// Sets a CSS selector to wait for before conversion.
/// Chromium will delay conversion until the specified element appears in the DOM.
/// </summary>
/// <param name="selector">A validated CSS selector.</param>
/// <returns>The builder instance for method chaining.</returns>
public HtmlConversionBehaviorBuilder SetWaitForSelector(CssSelector selector)
{
_htmlConversionBehaviors.WaitForSelector = selector ?? throw new ArgumentNullException(nameof(selector));

return this;
}

/// <summary>
/// Sets a CSS selector to wait for before conversion.
/// Chromium will delay conversion until the specified element appears in the DOM.
/// </summary>
/// <param name="selector">A CSS selector string (e.g., "#content", ".loaded").</param>
/// <returns>The builder instance for method chaining.</returns>
public HtmlConversionBehaviorBuilder SetWaitForSelector(string selector)
{
return SetWaitForSelector(CssSelector.Create(selector));
}

/// <summary>
/// Adds a CSS media feature override for Chromium rendering.
/// </summary>
/// <param name="feature">A validated emulated media feature.</param>
/// <returns>The builder instance for method chaining.</returns>
public HtmlConversionBehaviorBuilder AddEmulatedMediaFeature(EmulatedMediaFeature feature)
{
if (feature == null) throw new ArgumentNullException(nameof(feature));

_htmlConversionBehaviors.EmulatedMediaFeatures ??= new List<EmulatedMediaFeature>();
_htmlConversionBehaviors.EmulatedMediaFeatures.Add(feature);

return this;
}

/// <summary>
/// Adds a CSS media feature override by name and value.
/// </summary>
/// <param name="name">CSS media feature name (e.g., "prefers-color-scheme").</param>
/// <param name="value">CSS media feature value (e.g., "dark").</param>
/// <returns>The builder instance for method chaining.</returns>
public HtmlConversionBehaviorBuilder AddEmulatedMediaFeature(string name, string value)
{
return AddEmulatedMediaFeature(EmulatedMediaFeature.Create(name, value));
}

/// <summary>
/// Sets HTTP status codes that trigger a 409 Conflict when the main page returns them.
/// </summary>
/// <param name="statusCodes">Validated HTTP status codes.</param>
/// <returns>The builder instance for method chaining.</returns>
public HtmlConversionBehaviorBuilder SetFailOnHttpStatusCodes(IEnumerable<GotenbergStatusCode> statusCodes)
{
if (statusCodes == null) throw new ArgumentNullException(nameof(statusCodes));

var codes = statusCodes.ToList();

if (codes.Any(c => c == null))
throw new ArgumentException("Status codes collection must not contain null elements.", nameof(statusCodes));

_htmlConversionBehaviors.FailOnHttpStatusCodes = codes;

return this;
}

/// <summary>
/// Sets HTTP status codes that trigger a 409 Conflict when the main page returns them.
/// </summary>
/// <param name="statusCodes">Raw HTTP status code integers (must be 100-599).</param>
/// <returns>The builder instance for method chaining.</returns>
public HtmlConversionBehaviorBuilder SetFailOnHttpStatusCodes(params int[] statusCodes)
{
if (statusCodes == null) throw new ArgumentNullException(nameof(statusCodes));

return SetFailOnHttpStatusCodes(statusCodes.Select(GotenbergStatusCode.Create));
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/// <summary>
/// Sets HTTP status codes that trigger a failure when page resources return them.
/// </summary>
/// <param name="statusCodes">Validated HTTP status codes.</param>
/// <returns>The builder instance for method chaining.</returns>
public HtmlConversionBehaviorBuilder SetFailOnResourceHttpStatusCodes(IEnumerable<GotenbergStatusCode> statusCodes)
{
if (statusCodes == null) throw new ArgumentNullException(nameof(statusCodes));

var codes = statusCodes.ToList();

if (codes.Any(c => c == null))
throw new ArgumentException("Status codes collection must not contain null elements.", nameof(statusCodes));

_htmlConversionBehaviors.FailOnResourceHttpStatusCodes = codes;

return this;
}

/// <summary>
/// Sets HTTP status codes that trigger a failure when page resources return them.
/// </summary>
/// <param name="statusCodes">Raw HTTP status code integers (must be 100-599).</param>
/// <returns>The builder instance for method chaining.</returns>
public HtmlConversionBehaviorBuilder SetFailOnResourceHttpStatusCodes(params int[] statusCodes)
{
if (statusCodes == null) throw new ArgumentNullException(nameof(statusCodes));

return SetFailOnResourceHttpStatusCodes(statusCodes.Select(GotenbergStatusCode.Create));
}

/// <summary>
/// Adds a domain to exclude from HTTP status code checks on resources.
/// </summary>
/// <param name="domain">A validated domain name.</param>
/// <returns>The builder instance for method chaining.</returns>
public HtmlConversionBehaviorBuilder AddIgnoreResourceHttpStatusDomain(DomainName domain)
{
if (domain == null) throw new ArgumentNullException(nameof(domain));

_htmlConversionBehaviors.IgnoreResourceHttpStatusDomains ??= new List<DomainName>();
_htmlConversionBehaviors.IgnoreResourceHttpStatusDomains.Add(domain);

return this;
}

/// <summary>
/// Adds a domain to exclude from HTTP status code checks on resources.
/// </summary>
/// <param name="domain">A domain string (e.g., "cdn.example.com").</param>
/// <returns>The builder instance for method chaining.</returns>
public HtmlConversionBehaviorBuilder AddIgnoreResourceHttpStatusDomain(string domain)
{
return AddIgnoreResourceHttpStatusDomain(DomainName.Create(domain));
}

/// <summary>
/// Adds multiple domains to exclude from HTTP status code checks on resources.
/// </summary>
/// <param name="domains">Domain strings to exclude.</param>
/// <returns>The builder instance for method chaining.</returns>
public HtmlConversionBehaviorBuilder AddIgnoreResourceHttpStatusDomains(params string[] domains)
{
if (domains == null) throw new ArgumentNullException(nameof(domains));

var validated = domains.Select(DomainName.Create).ToList();

_htmlConversionBehaviors.IgnoreResourceHttpStatusDomains ??= new List<DomainName>();
_htmlConversionBehaviors.IgnoreResourceHttpStatusDomains.AddRange(validated);

Comment thread
coderabbitai[bot] marked this conversation as resolved.
return this;
}

/// <summary>
/// Tells Gotenberg to return a 409 Conflict if any resource fails to load due to network errors.
/// </summary>
/// <returns>The builder instance for method chaining.</returns>
public HtmlConversionBehaviorBuilder FailOnResourceLoadingFailed()
{
_htmlConversionBehaviors.FailOnResourceLoadingFailed = true;

return this;
}

/// <summary>
/// Sets the format of the resulting PDF document.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,15 @@
return value switch
{
PdfFormat format => format.ToFormDataValue(),
LibrePdfFormats format => format.ToFormDataValue(),

Check warning on line 80 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(LibrePdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 80 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(LibrePdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 80 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(LibrePdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 80 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(LibrePdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 80 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(LibrePdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 80 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(LibrePdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 80 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(LibrePdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 80 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(LibrePdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 80 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(LibrePdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 80 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(LibrePdfFormats)' is obsolete: 'Use PdfFormat instead'
ConversionPdfFormats format => format.ToFormDataValue(),

Check warning on line 81 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(ConversionPdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 81 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(ConversionPdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 81 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(ConversionPdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 81 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(ConversionPdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 81 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(ConversionPdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 81 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(ConversionPdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 81 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(ConversionPdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 81 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(ConversionPdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 81 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(ConversionPdfFormats)' is obsolete: 'Use PdfFormat instead'

Check warning on line 81 in src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

View workflow job for this annotation

GitHub Actions / build (8.x)

'EnumExtensions.ToFormDataValue(ConversionPdfFormats)' is obsolete: 'Use PdfFormat instead'
PdfPassword password => password.Value,
List<Cookie> cookies => JsonConvert.SerializeObject(cookies),
List<EmulatedMediaFeature> features => JsonConvert.SerializeObject(
features.ToDictionary(f => f.Name, f => f.Value)),
Comment on lines +84 to +85
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

For Gotenberg v8 Chromium routes, what is the exact expected form value shape for emulatedMediaFeatures(JSON array of{name,value} objects vs JSON object map)?

💡 Result:

For Gotenberg v8 Chromium routes, the exact expected form value shape for emulatedMediaFeatures is a JSON array of {name, value} objects. It is not a JSON object map.

Citations:


🏁 Script executed:

# Find and examine the EmulatedMediaFeature class
find . -name "EmulatedMediaFeature.cs" -type f | head -5

Repository: ChangemakerStudios/GotenbergSharpApiClient

Length of output: 162


🏁 Script executed:

cat -n ./src/Gotenberg.Sharp.Api.Client/Domain/ValueObjects/EmulatedMediaFeature.cs

Repository: ChangemakerStudios/GotenbergSharpApiClient

Length of output: 3573


🏁 Script executed:

# Examine the FacetBase.cs file around lines 83-84
sed -n '75,95p' ./src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs

Repository: ChangemakerStudios/GotenbergSharpApiClient

Length of output: 1184


Serialize emulatedMediaFeatures as a list, not a dictionary.

Lines 83-84 currently convert features to a dictionary via features.ToDictionary(f => f.Name, f => f.Value), which produces a JSON object instead of the required JSON array of {name, value} objects. This violates the Gotenberg v8 API contract documented in EmulatedMediaFeature.cs (line 23). Additionally, ToDictionary() throws ArgumentException on duplicate feature names, creating avoidable runtime failures.

Serialize the list directly to preserve the array structure; the class's [JsonProperty] attributes ensure correct JSON output:

💡 Proposed fix
-            List<EmulatedMediaFeature> features => JsonConvert.SerializeObject(
-                features.ToDictionary(f => f.Name, f => f.Value)),
+            List<EmulatedMediaFeature> features => JsonConvert.SerializeObject(features),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
List<EmulatedMediaFeature> features => JsonConvert.SerializeObject(
features.ToDictionary(f => f.Name, f => f.Value)),
List<EmulatedMediaFeature> features => JsonConvert.SerializeObject(features),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Gotenberg.Sharp.Api.Client/Domain/Requests/Facets/FacetBase.cs` around
lines 83 - 84, The code in FacetBase.cs is serializing emulated media features
into a JSON object by using features.ToDictionary(...) which both produces the
wrong shape and can throw on duplicate names; change the serialization to
serialize the List<EmulatedMediaFeature> directly (e.g.,
JsonConvert.SerializeObject(features)) so the output is a JSON array of
{name,value} objects as defined by EmulatedMediaFeature and you avoid
ToDictionary’s ArgumentException.

List<GotenbergStatusCode> codes => JsonConvert.SerializeObject(codes.Select(c => c.Value)),
List<DomainName> domains => JsonConvert.SerializeObject(domains.Select(d => d.Value)),
CssSelector selector => selector.Value,
OverlaySource overlaySource => overlaySource.ToFormValue(),
SplitMode splitMode => splitMode.ToFormValue(),
float f => f.ToString(cultureInfo),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

using Gotenberg.Sharp.API.Client.Domain.ValueObjects;

using Newtonsoft.Json.Linq;

namespace Gotenberg.Sharp.API.Client.Domain.Requests.Facets;
Expand Down Expand Up @@ -85,4 +87,44 @@ public class HtmlConversionBehaviors : FacetBase
/// </summary>
[MultiFormHeader(Constants.Gotenberg.Chromium.Shared.HtmlConvert.SkipNetworkIdleEvent)]
public bool? SkipNetworkIdleEvent { get; set; }

/// <summary>
/// CSS selector to wait for before conversion. Delays until the element appears in the DOM.
/// </summary>
[MultiFormHeader(Constants.Gotenberg.Chromium.Shared.HtmlConvert.WaitForSelector)]
public CssSelector? WaitForSelector { get; set; }

/// <summary>
/// Overrides CSS media features (e.g., prefers-color-scheme, prefers-reduced-motion).
/// Sent as a JSON array of {name, value} objects.
/// </summary>
[MultiFormHeader(Constants.Gotenberg.Chromium.Shared.HtmlConvert.EmulatedMediaFeatures)]
public List<EmulatedMediaFeature>? EmulatedMediaFeatures { get; set; }

/// <summary>
/// HTTP status codes that trigger a 409 Conflict response from Gotenberg
/// when the main page returns a matching code. Default: [499, 599].
/// </summary>
[MultiFormHeader(Constants.Gotenberg.Chromium.Shared.HtmlConvert.FailOnHttpStatusCodes)]
public List<GotenbergStatusCode>? FailOnHttpStatusCodes { get; set; }

/// <summary>
/// HTTP status codes that trigger a failure when page resources (CSS, images, fonts)
/// return a matching code.
/// </summary>
[MultiFormHeader(Constants.Gotenberg.Chromium.Shared.HtmlConvert.FailOnResourceHttpStatusCodes)]
public List<GotenbergStatusCode>? FailOnResourceHttpStatusCodes { get; set; }

/// <summary>
/// Domains to exclude from HTTP status code checks on resources.
/// Useful for ignoring third-party CDNs or analytics domains.
/// </summary>
[MultiFormHeader(Constants.Gotenberg.Chromium.Shared.HtmlConvert.IgnoreResourceHttpStatusDomains)]
public List<DomainName>? IgnoreResourceHttpStatusDomains { get; set; }

/// <summary>
/// Tells Gotenberg to return a 409 Conflict if any resource fails to load due to network errors.
/// </summary>
[MultiFormHeader(Constants.Gotenberg.Chromium.Shared.HtmlConvert.FailOnResourceLoadingFailed)]
public bool? FailOnResourceLoadingFailed { get; set; }
}
Loading
Loading