-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathHtmlConversionBehaviorBuilder.cs
More file actions
388 lines (323 loc) · 14.7 KB
/
HtmlConversionBehaviorBuilder.cs
File metadata and controls
388 lines (323 loc) · 14.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
// Copyright 2019-2025 Chris Mohan, Jaben Cargman
// and GotenbergSharpApiClient Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// 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;
/// <summary>
/// Configures Chromium rendering behaviors for HTML and URL to PDF conversions.
/// Includes settings for wait delays, HTTP headers, cookies, media emulation, and error handling.
/// </summary>
/// <remarks>
/// PDF output options (PDF/A, PDF/UA, flatten, tagged PDF, metadata) have moved to
/// <see cref="PdfOutputOptionsBuilder"/> which is available via <c>SetPdfOutputOptions()</c> on all builders.
/// </remarks>
public sealed class HtmlConversionBehaviorBuilder
{
private readonly HtmlConversionBehaviors _htmlConversionBehaviors;
internal HtmlConversionBehaviorBuilder(HtmlConversionBehaviors htmlConversionBehaviors)
{
_htmlConversionBehaviors = htmlConversionBehaviors;
}
/// <summary>
/// Sets the wait duration when loading an HTML document before converting it to PDF
/// </summary>
/// <param name="seconds"></param>
/// <returns></returns>
/// <remarks>Prefer <see cref="SetBrowserWaitExpression" /> over waitDelay.</remarks>
public HtmlConversionBehaviorBuilder SetBrowserWaitDelay(int seconds)
{
_htmlConversionBehaviors.WaitDelay = $"{seconds}s";
return this;
}
/// <summary>
/// Sets a java-script expression to wait before converting an HTML document to PDF until it returns true
/// </summary>
/// <param name="expression">The expression to set</param>
/// <returns></returns>
/// <remarks>Prefer this option over waitDelay.</remarks>
/// <example>SetBrowserWaitExpression("window.status === 'ready'")</example>
/// <exception cref="InvalidOperationException"></exception>
public HtmlConversionBehaviorBuilder SetBrowserWaitExpression(string expression)
{
if (expression.IsNotSet())
{
throw new InvalidOperationException("expression is not set");
}
_htmlConversionBehaviors.WaitForExpression = expression;
return this;
}
/// <summary>
/// Overrides the default User-Agent extraHeaders
/// </summary>
/// <param name="userAgent"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
[Obsolete("Deprecated in Gotenberg v8+")]
public HtmlConversionBehaviorBuilder SetUserAgent(string userAgent)
{
if (userAgent.IsNotSet())
{
throw new InvalidOperationException("headerName is not set");
}
_htmlConversionBehaviors.UserAgent = userAgent;
return this;
}
/// <summary>
/// Adds custom HTTP headers that Chromium will send when loading the HTML. Useful for authentication tokens,
/// custom request identification, or triggering specific server behavior.
/// </summary>
/// <param name="headerName">HTTP header name.</param>
/// <param name="headerValue">HTTP header value.</param>
/// <returns>The builder instance for method chaining.</returns>
/// <exception cref="InvalidOperationException">Thrown when header name or value is invalid.</exception>
public HtmlConversionBehaviorBuilder AddAdditionalHeaders(string headerName, string headerValue)
{
var header = string.Format("{0}{2}{1}", "{", "}", $"{'"'}{headerName}{'"'} : {'"'}{headerValue}{'"'}");
return AddAdditionalHeaders(JObject.Parse(header));
}
/// <summary>
/// Adds multiple custom HTTP headers as a JSON object. Useful for adding several headers at once.
/// </summary>
/// <param name="extraHeaders">JSON object containing header name-value pairs.</param>
/// <returns>The builder instance for method chaining.</returns>
/// <exception cref="InvalidOperationException">Thrown when extraHeaders is null.</exception>
public HtmlConversionBehaviorBuilder AddAdditionalHeaders(JObject extraHeaders)
{
if (extraHeaders == null)
{
throw new InvalidOperationException("extraHeaders is null");
}
_htmlConversionBehaviors.ExtraHeaders = extraHeaders;
return this;
}
/// <summary>
/// Adds a cookie to store in the Chromium cookie jar.
/// </summary>
/// <param name="cookie">The cookie to add</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public HtmlConversionBehaviorBuilder AddCookie(Cookie cookie)
{
if (cookie == null)
{
throw new ArgumentNullException(nameof(cookie));
}
_htmlConversionBehaviors.Cookies ??= new List<Cookie>();
Cookie.Validate(cookie);
_htmlConversionBehaviors.Cookies.Add(cookie);
return this;
}
/// <summary>
/// Tells gotenberg to return a 409 response if there are exceptions in the Chromium console.
/// </summary>
/// <returns></returns>
public HtmlConversionBehaviorBuilder FailOnConsoleExceptions()
{
_htmlConversionBehaviors.FailOnConsoleExceptions = true;
return this;
}
/// <summary>
/// Configures gotenberg to emulate html loading as screen. By default, it loads it as print
/// </summary>
/// <returns></returns>
public HtmlConversionBehaviorBuilder EmulateAsScreen()
{
_htmlConversionBehaviors.EmulatedMediaType = "screen";
return this;
}
/// <summary>
/// Gotenberg 8+ ONLY: Configures gotenberg to not wait for Chromium network to be idle.
/// </summary>
/// <returns></returns>
public HtmlConversionBehaviorBuilder SkipNetworkIdleEvent()
{
_htmlConversionBehaviors.SkipNetworkIdleEvent = true;
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));
}
/// <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);
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>
[Obsolete("Use SetPdfOutputOptions(o => o.SetPdfFormat(...)) on the builder instead")]
public HtmlConversionBehaviorBuilder SetPdfFormat(ConversionPdfFormats format)
{
return this;
}
/// <summary>
/// This tells gotenberg to enable Universal Access for the resulting PDF.
/// </summary>
[Obsolete("Use SetPdfOutputOptions(o => o.SetPdfUa()) on the builder instead")]
public HtmlConversionBehaviorBuilder SetPdfUa(bool enablePdfUa = true)
{
return this;
}
/// <summary>
/// This tells gotenberg to enable embeds logical structure tags for accessibility during generation.
/// </summary>
[Obsolete("Use SetPdfOutputOptions(o => o.SetGenerateTaggedPdf()) on the builder instead")]
public HtmlConversionBehaviorBuilder SetGenerateTaggedPdf(bool generateTaggedPdf = true)
{
return this;
}
/// <summary>
/// Sets the document metadata.
/// </summary>
[Obsolete("Use SetPdfOutputOptions(o => o.SetMetadata(...)) on the builder instead")]
public HtmlConversionBehaviorBuilder SetMetadata(IDictionary<string, object> dictionary)
{
return this;
}
/// <summary>
/// Sets the document metadata.
/// </summary>
[Obsolete("Use SetPdfOutputOptions(o => o.SetMetadata(...)) on the builder instead")]
public HtmlConversionBehaviorBuilder SetMetadata(JObject metadata)
{
return this;
}
}