View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit;
16  
17  import java.io.File;
18  import java.io.IOException;
19  import java.io.InputStream;
20  import java.io.Serializable;
21  import java.net.InetAddress;
22  import java.net.URL;
23  import java.security.KeyStore;
24  import java.security.KeyStoreException;
25  import java.security.NoSuchAlgorithmException;
26  import java.security.cert.CertificateException;
27  
28  import javax.net.ssl.SSLContext;
29  
30  import org.apache.commons.io.FileUtils;
31  
32  /**
33   * Configuration options for {@link WebClient} instances.
34   * This class provides fine-grained control over client behavior including:
35   * <ul>
36   *   <li>JavaScript and CSS processing</li>
37   *   <li>SSL/TLS configuration and certificates</li>
38   *   <li>HTTP timeouts and proxy settings</li>
39   *   <li>Memory management and temporary file handling</li>
40   *   <li>WebSocket and geolocation support</li>
41   * </ul>
42   *
43   * <p>All options have sensible defaults and can be modified independently.</p>
44   *
45   * @author Ahmed Ashour
46   * @author Marc Guillemot
47   * @author Madis Pärn
48   * @author Ronald Brill
49   */
50  @SuppressWarnings("PMD.TooManyFields")
51  public class WebClientOptions implements Serializable {
52  
53      /** 1920. */
54      private static final int DEFAULT_SCRREN_WIDTH = 1920;
55      /** 1080. */
56      private static final int DEFAULT_SCRREN_HEIGHT = 1080;
57  
58      private boolean javaScriptEnabled_ = true;
59      private boolean cssEnabled_ = true;
60      private boolean printContentOnFailingStatusCode_ = true;
61      private boolean throwExceptionOnFailingStatusCode_ = true;
62      private boolean throwExceptionOnScriptError_ = true;
63      private boolean popupBlockerEnabled_;
64      private boolean isRedirectEnabled_ = true;
65      // strange value 72 used to be backward compatible with 4.14.0
66      private int pageRefreshLimit_ = 72;
67      private File tempFileDirectory_;
68  
69      private transient KeyStore sslClientCertificateStore_;
70      private char[] sslClientCertificatePassword_;
71      private transient KeyStore sslTrustStore_;
72      private String[] sslClientProtocols_;
73      private String[] sslClientCipherSuites_;
74  
75      private transient SSLContext sslContext_;
76      private boolean useInsecureSSL_; // default is secure SSL
77      private String sslInsecureProtocol_;
78  
79      private boolean doNotTrackEnabled_;
80      private String homePage_ = "https://www.htmlunit.org/";
81      private ProxyConfig proxyConfig_;
82      private int timeout_ = 90_000; // like Firefox 16 default's value for network.http.connection-timeout
83      private long connectionTimeToLive_ = -1; // HttpClient default
84  
85      private boolean fileProtocolForXMLHttpRequestsAllowed_;
86  
87      private int maxInMemory_ = 500 * 1024;
88      private int historySizeLimit_ = 50;
89      private int historyPageCacheLimit_ = Integer.MAX_VALUE;
90      private InetAddress localAddress_;
91      private boolean downloadImages_;
92      private int screenWidth_ = DEFAULT_SCRREN_WIDTH;
93      private int screenHeight_ = DEFAULT_SCRREN_HEIGHT;
94  
95      private boolean geolocationEnabled_;
96      private Geolocation geolocation_;
97  
98      private int nekoReaderBufferSize_ = -1;
99  
100     private boolean webSocketEnabled_ = true;
101     private int webSocketMaxTextMessageSize_ = -1;
102     private int webSocketMaxTextMessageBufferSize_ = -1;
103     private int webSocketMaxBinaryMessageSize_ = -1;
104     private int webSocketMaxBinaryMessageBufferSize_ = -1;
105 
106     private boolean isFetchPolyfillEnabled_;
107 
108     /**
109      * Sets the SSLContext; if this is set it is used and some other settings are ignored
110      * (protocol, keyStore, keyStorePassword, trustStore, sslClientCertificateStore, sslClientCertificatePassword).
111      * <p>This property is transient (because SSLContext is not serializable)
112      * @param sslContext the SSLContext, {@code null} to use for default value
113      */
114     public void setSSLContext(final SSLContext sslContext) {
115         sslContext_ = sslContext;
116     }
117 
118     /**
119      * Gets the SSLContext; if this is set this is used and some other settings are ignored
120      * (protocol, keyStore, keyStorePassword, trustStore, sslClientCertificateStore, sslClientCertificatePassword).
121      * <p>This property is transient (because SSLContext is not serializable)
122      * @return the SSLContext
123      */
124     public SSLContext getSSLContext() {
125         return sslContext_;
126     }
127 
128     /**
129      * If set to {@code true}, the client will accept connections to any host, regardless of
130      * whether they have valid certificates or not. This is especially useful when you are trying to
131      * connect to a server with expired or corrupt certificates.
132      * @param useInsecureSSL whether or not to use insecure SSL
133      */
134     public void setUseInsecureSSL(final boolean useInsecureSSL) {
135         useInsecureSSL_ = useInsecureSSL;
136     }
137 
138     /**
139      * Indicates if insecure SSL should be used.
140      * @return {@code true} if insecure SSL should be used. Default is {@code false}.
141      */
142     public boolean isUseInsecureSSL() {
143         return useInsecureSSL_;
144     }
145 
146     /**
147      * Sets whether or not redirections will be followed automatically on receipt of a redirect
148      * status code from the server.
149      * @param enabled true to enable automatic redirection
150      */
151     public void setRedirectEnabled(final boolean enabled) {
152         isRedirectEnabled_ = enabled;
153     }
154 
155     /**
156      * Sets the redirect limit for page refresh operations using HTTP refresh headers or meta tags.
157      * This prevents infinite refresh loops by limiting the number of consecutive refreshes allowed.
158      * Set to -1 to allow unlimited refreshes.
159      *
160      * <p>Note: The {@link NiceRefreshHandler} and {@link ImmediateRefreshHandler}
161      * have additional loop protection that may trigger before this limit.</p>
162      *
163      * @param pageRefreshLimit the maximum number of refresh loops, or -1 for unlimited
164      */
165     public void setPageRefreshLimit(final int pageRefreshLimit) {
166         pageRefreshLimit_ = pageRefreshLimit;
167     }
168 
169     /**
170      * Returns the directory to be used for storing the response content in
171      * a temporary file see {@link #getMaxInMemory()}.
172      * @return the directory to be used for storing temp files or null to use the system default
173      */
174     public File getTempFileDirectory() {
175         return tempFileDirectory_;
176     }
177 
178     /**
179      * Sets the directory to be used for storing response content in temporary files.
180      * See {@link #setMaxInMemory(int)} for when temporary files are created.
181      * If the directory doesn't exist, it will be created automatically.
182      *
183      * @param tempFileDirectory the directory to use, or {@code null} for system default
184      * @throws IOException if directory creation fails
185      * @throws IllegalArgumentException if the path points to an existing file
186      */
187     public void setTempFileDirectory(final File tempFileDirectory) throws IOException {
188         if (tempFileDirectory != null) {
189             if (tempFileDirectory.exists() && !tempFileDirectory.isDirectory()) {
190                 throw new IllegalArgumentException("The provided file '" + tempFileDirectory
191                         + "' points to an already existing file");
192             }
193 
194             if (!tempFileDirectory.exists()) {
195                 FileUtils.forceMkdir(tempFileDirectory);
196             }
197         }
198         tempFileDirectory_ = tempFileDirectory;
199     }
200 
201     /**
202      * Returns whether or not redirections will be followed automatically on receipt of
203      * a redirect status code from the server.
204      * @return true if automatic redirection is enabled
205      */
206     public boolean isRedirectEnabled() {
207         return isRedirectEnabled_;
208     }
209 
210     /**
211      * Returns the limit to be used when a page refreshes itself by using a
212      * http refresh header or meta tag. Negative values are interpreted as
213      * endless refresh support.
214      *
215      * @return pageRefreshLimit the number of refresh loops before throwing an exception
216      */
217     public int getPageRefreshLimit() {
218         return pageRefreshLimit_;
219     }
220 
221     /**
222      * Sets the SSL client certificate {@link KeyStore} to use.
223      * <p>
224      * If the web server requires Renegotiation, you have to set system property
225      * "sun.security.ssl.allowUnsafeRenegotiation" to true, as hinted in
226      * <a href="http://www.oracle.com/technetwork/java/javase/documentation/tlsreadme2-176330.html">
227      * TLS Renegotiation Issue</a>.
228      * <p>
229      * In some cases the impl seems to pick old certificates from the {@link KeyStore}. To avoid
230      * that, wrap your {@link KeyStore} inside your own {@link KeyStore} impl and filter out outdated
231      * certificates.
232      * <p>This property is transient (because KeyStore is not serializable)
233      *
234      * @param keyStore {@link KeyStore} to use
235      * @param keyStorePassword the keystore password
236      */
237     public void setSSLClientCertificateKeyStore(final KeyStore keyStore, final char[] keyStorePassword) {
238         sslClientCertificateStore_ = keyStore;
239         sslClientCertificatePassword_ = keyStorePassword;
240     }
241 
242     /**
243      * Sets the SSL client certificate to use.
244      * The needed parameters are used to construct a {@link java.security.KeyStore}.
245      * <p>
246      * If the web server requires Renegotiation, you have to set system property
247      * "sun.security.ssl.allowUnsafeRenegotiation" to true, as hinted in
248      * <a href="http://www.oracle.com/technetwork/java/javase/documentation/tlsreadme2-176330.html">
249      * TLS Renegotiation Issue</a>.
250      * <p>This property is transient (because KeyStore is not serializable)
251      *
252      * @param keyStoreUrl the URL which locates the certificate {@link KeyStore}
253      * @param keyStorePassword the certificate {@link KeyStore} password
254      * @param keyStoreType the type of certificate {@link KeyStore}, usually {@code jks} or {@code pkcs12}
255      *
256      */
257     public void setSSLClientCertificateKeyStore(final URL keyStoreUrl, final String keyStorePassword,
258             final String keyStoreType) {
259         try (InputStream is = keyStoreUrl.openStream()) {
260             sslClientCertificateStore_ = getKeyStore(is, keyStorePassword, keyStoreType);
261             sslClientCertificatePassword_ = keyStorePassword == null ? null : keyStorePassword.toCharArray();
262         }
263         catch (final Exception e) {
264             throw new RuntimeException(e);
265         }
266     }
267 
268     /**
269      * Sets the SSL client certificate {@link KeyStore} to use. The parameters are used to
270      * construct the {@link KeyStore}.
271      * <p>
272      * If the web server requires Renegotiation, you have to set system property
273      * "sun.security.ssl.allowUnsafeRenegotiation" to true, as hinted in
274      * <a href="http://www.oracle.com/technetwork/java/javase/documentation/tlsreadme2-176330.html">
275      * TLS Renegotiation Issue</a>.
276      * <p>
277      * In some cases the impl seems to pick old certificates from the {@link KeyStore}. To avoid
278      * that, wrap your {@link KeyStore} inside your own {@link KeyStore} impl and filter out outdated
279      * certificates. Provide the {@link KeyStore} to the options instead of the input stream.
280      *
281      * @param keyStoreInputStream the input stream which represents the {@link KeyStore} holding the certificates
282      * @param keyStorePassword the {@link KeyStore} password
283      * @param keyStoreType the type of {@link KeyStore}, usually {@code jks} or {@code pkcs12}
284      */
285     public void setSSLClientCertificateKeyStore(final InputStream keyStoreInputStream,
286             final String keyStorePassword, final String keyStoreType) {
287         try {
288             setSSLClientCertificateKeyStore(
289                     getKeyStore(keyStoreInputStream, keyStorePassword, keyStoreType),
290                     keyStorePassword.toCharArray());
291         }
292         catch (final Exception e) {
293             throw new RuntimeException(e);
294         }
295     }
296 
297     /**
298      * Gets the SSLClientCertificateStore.
299      * <p>This property is transient (because KeyStore is not serializable)
300      *
301      * @return the KeyStore for use on SSL connections
302      */
303     public KeyStore getSSLClientCertificateStore() {
304         return sslClientCertificateStore_;
305     }
306 
307     /**
308      * Gets the SSLClientCertificatePassword.
309      * @return the password
310      */
311     public char[] getSSLClientCertificatePassword() {
312         return sslClientCertificatePassword_;
313     }
314 
315     /**
316      * Gets the protocol versions enabled for use on SSL connections.
317      * @return the protocol versions enabled for use on SSL connections
318      * @see #setSSLClientProtocols(String...)
319      */
320     public String[] getSSLClientProtocols() {
321         return sslClientProtocols_;
322     }
323 
324     /**
325      * Sets the protocol versions enabled for use on SSL connections,
326      * {@code null} to use default ones.
327      *
328      * @param sslClientProtocols the protocol versions
329      * @see javax.net.ssl.SSLSocket#setEnabledProtocols(String[])
330      * @see #getSSLClientProtocols()
331      * @see #setSSLClientCipherSuites(String...)
332      * @see #setUseInsecureSSL(boolean)
333      */
334     public void setSSLClientProtocols(final String... sslClientProtocols) {
335         sslClientProtocols_ = sslClientProtocols;
336     }
337 
338     /**
339      * Gets the cipher suites enabled for use on SSL connections.
340      * @return the cipher suites enabled for use on SSL connections
341      * @see #setSSLClientCipherSuites(String...)
342      */
343     public String[] getSSLClientCipherSuites() {
344         return sslClientCipherSuites_;
345     }
346 
347     /**
348      * Sets the cipher suites enabled for use on SSL connections,
349      * {@code null} to use default ones.
350      *
351      * @param sslClientCipherSuites the cipher suites
352      * @see javax.net.ssl.SSLSocket#setEnabledCipherSuites(String[])
353      * @see #getSSLClientCipherSuites()
354      */
355     public void setSSLClientCipherSuites(final String... sslClientCipherSuites) {
356         sslClientCipherSuites_ = sslClientCipherSuites;
357     }
358 
359     /**
360      * Enables/disables JavaScript support. By default, this property is enabled.
361      *
362      * @param enabled {@code true} to enable JavaScript support
363      */
364     public void setJavaScriptEnabled(final boolean enabled) {
365         javaScriptEnabled_ = enabled;
366     }
367 
368     /**
369      * Returns {@code true} if JavaScript is enabled and the script engine was loaded successfully.
370      *
371      * @return {@code true} if JavaScript is enabled
372      */
373     public boolean isJavaScriptEnabled() {
374         return javaScriptEnabled_;
375     }
376 
377     /**
378      * Enables/disables CSS support. By default, this property is enabled.
379      * If disabled HtmlUnit will not download the linked css files and also
380      * not triggered the associated onload/onerror events.
381      *
382      * @param enabled {@code true} to enable CSS support
383      */
384     public void setCssEnabled(final boolean enabled) {
385         cssEnabled_ = enabled;
386     }
387 
388     /**
389      * Returns {@code true} if CSS is enabled.
390      *
391      * @return {@code true} if CSS is enabled
392      */
393     public boolean isCssEnabled() {
394         return cssEnabled_;
395     }
396 
397     /**
398      * Enable/disable the popup window blocker. By default, the popup blocker is disabled, and popup
399      * windows are allowed. When set to {@code true}, <code>window.open()</code> has no effect and
400      * returns {@code null}.
401      *
402      * @param enabled {@code true} to enable the popup window blocker
403      */
404     public void setPopupBlockerEnabled(final boolean enabled) {
405         popupBlockerEnabled_ = enabled;
406     }
407 
408     /**
409      * Returns {@code true} if the popup window blocker is enabled.
410      *
411      * @return {@code true} if the popup window blocker is enabled
412      */
413     public boolean isPopupBlockerEnabled() {
414         return popupBlockerEnabled_;
415     }
416 
417     /**
418      * Enables/disables "Do Not Track" support. By default, this property is disabled.
419      *
420      * @param enabled {@code true} to enable "Do Not Track" support
421      */
422     public void setDoNotTrackEnabled(final boolean enabled) {
423         doNotTrackEnabled_ = enabled;
424     }
425 
426     /**
427      * Returns {@code true} if "Do Not Track" is enabled.
428      *
429      * @return {@code true} if "Do Not Track" is enabled
430      */
431     public boolean isDoNotTrackEnabled() {
432         return doNotTrackEnabled_;
433     }
434 
435     /**
436      * Specify whether or not the content of the resulting document will be
437      * printed to the console in the event of a failing response code.
438      * Successful response codes are in the range 200-299. The default is true.
439      *
440      * @param enabled True to enable this feature
441      */
442     public void setPrintContentOnFailingStatusCode(final boolean enabled) {
443         printContentOnFailingStatusCode_ = enabled;
444     }
445 
446     /**
447      * Returns {@code true} if the content of the resulting document will be printed to
448      * the console in the event of a failing response code.
449      *
450      * @return {@code true} if the content of the resulting document will be printed to
451      *         the console in the event of a failing response code
452      * @see #setPrintContentOnFailingStatusCode
453      */
454     public boolean isPrintContentOnFailingStatusCode() {
455         return printContentOnFailingStatusCode_;
456     }
457 
458     /**
459      * Specify whether or not an exception will be thrown in the event of a
460      * failing status code. Successful status codes are in the range 200-299.
461      * The default is true.
462      *
463      * @param enabled {@code true} to enable this feature
464      */
465     public void setThrowExceptionOnFailingStatusCode(final boolean enabled) {
466         throwExceptionOnFailingStatusCode_ = enabled;
467     }
468 
469     /**
470      * Returns {@code true} if an exception will be thrown in the event of a failing response code.
471      * @return {@code true} if an exception will be thrown in the event of a failing response code
472      * @see #setThrowExceptionOnFailingStatusCode
473      */
474     public boolean isThrowExceptionOnFailingStatusCode() {
475         return throwExceptionOnFailingStatusCode_;
476     }
477 
478     /**
479      * Indicates if an exception should be thrown when a script execution fails
480      * (the default) or if it should be caught and just logged to allow page
481      * execution to continue.
482      * @return {@code true} if an exception is thrown on script error (the default)
483      */
484     public boolean isThrowExceptionOnScriptError() {
485         return throwExceptionOnScriptError_;
486     }
487 
488     /**
489      * Changes the behavior of this webclient when a script error occurs.
490      * @param enabled indicates if exception should be thrown or not
491      */
492     public void setThrowExceptionOnScriptError(final boolean enabled) {
493         throwExceptionOnScriptError_ = enabled;
494     }
495 
496     /**
497      * Returns the client's current homepage.
498      * @return the client's current homepage
499      */
500     public String getHomePage() {
501         return homePage_;
502     }
503 
504     /**
505      * Sets the client's homepage.
506      * @param homePage the new homepage URL
507      */
508     public void setHomePage(final String homePage) {
509         homePage_ = homePage;
510     }
511 
512     /**
513      * Returns the proxy configuration for this client.
514      * @return the proxy configuration for this client
515      */
516     public ProxyConfig getProxyConfig() {
517         return proxyConfig_;
518     }
519 
520     /**
521      * Sets the proxy configuration for this client.
522      * @param proxyConfig the proxy configuration for this client
523      */
524     public void setProxyConfig(final ProxyConfig proxyConfig) {
525         WebAssert.notNull("proxyConfig", proxyConfig);
526         proxyConfig_ = proxyConfig;
527     }
528 
529     /**
530      * Gets the timeout value for the {@link WebConnection}.
531      * The default timeout is 90 seconds.
532      * @return the timeout value in milliseconds
533      * @see #setTimeout(int)
534      * @see #setConnectionTimeToLive(long)
535      */
536     public int getTimeout() {
537         return timeout_;
538     }
539 
540     /**
541      * <p>Sets the timeout of the {@link WebConnection}. Set to zero for an infinite wait.</p>
542      *
543      * <p>Note: The timeout is used twice. The first is for making the socket connection, the second is
544      * for data retrieval. If the time is critical you must allow for twice the time specified here.</p>
545      *
546      * @param timeout the value of the timeout in milliseconds
547      */
548     public void setTimeout(final int timeout) {
549         timeout_ = timeout;
550     }
551 
552     /**
553      * Gets the connTimeToLive value for the HttpClient connection pool.
554      *
555      * @return the timeout value in milliseconds
556      */
557     public long getConnectionTimeToLive() {
558         return connectionTimeToLive_;
559     }
560 
561     /**
562      * Sets the connection time-to-live for the HttpClient connection pool.
563      * This is useful when working with web pages behind DNS-based load balancers
564      * where IP addresses may change frequently.
565      *
566      * @param connectionTimeToLive the timeout in milliseconds, or -1 to disable (default)
567      */
568     public void setConnectionTimeToLive(final long connectionTimeToLive) {
569         connectionTimeToLive_ = connectionTimeToLive;
570     }
571 
572     /**
573      * Sets the SSL protocol, used only when {@link #setUseInsecureSSL(boolean)} is set to {@code true}.
574      * @param sslInsecureProtocol the SSL protocol for insecure SSL connections,
575      *      {@code null} to use for default value
576      */
577     public void setSSLInsecureProtocol(final String sslInsecureProtocol) {
578         sslInsecureProtocol_ = sslInsecureProtocol;
579     }
580 
581     /**
582      * Gets the SSL protocol, to be used only when {@link #setUseInsecureSSL(boolean)} is set to {@code true}.
583      * @return the SSL protocol for insecure SSL connections
584      */
585     public String getSSLInsecureProtocol() {
586         return sslInsecureProtocol_;
587     }
588 
589     /**
590      * Sets the SSL server certificate trust store. All server certificates will be validated against
591      * this trust store.
592      * <p>This property is transient (because KeyStore is not serializable)
593      * <p>The needed parameters are used to construct a {@link java.security.KeyStore}.
594      *
595      * @param sslTrustStoreUrl the URL which locates the trust store
596      * @param sslTrustStorePassword the trust store password
597      * @param sslTrustStoreType the type of trust store, usually {@code jks} or {@code pkcs12}
598      */
599     public void setSSLTrustStore(final URL sslTrustStoreUrl, final String sslTrustStorePassword,
600             final String sslTrustStoreType) {
601         try (InputStream is = sslTrustStoreUrl.openStream()) {
602             sslTrustStore_ = getKeyStore(is, sslTrustStorePassword, sslTrustStoreType);
603         }
604         catch (final Exception e) {
605             throw new RuntimeException(e);
606         }
607     }
608 
609     void setSSLTrustStore(final KeyStore keyStore) {
610         sslTrustStore_ = keyStore;
611     }
612 
613     /**
614      * Gets the SSL TrustStore.
615      * <p>This property is transient (because KeyStore is not serializable)
616      * @return the SSL TrustStore for insecure SSL connections
617      */
618     public KeyStore getSSLTrustStore() {
619         return sslTrustStore_;
620     }
621 
622     private static KeyStore getKeyStore(final InputStream inputStream, final String keystorePassword,
623             final String keystoreType)
624                     throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException {
625         if (inputStream == null) {
626             return null;
627         }
628 
629         final KeyStore keyStore = KeyStore.getInstance(keystoreType);
630         final char[] passwordChars = keystorePassword == null ? null : keystorePassword.toCharArray();
631         keyStore.load(inputStream, passwordChars);
632         return keyStore;
633     }
634 
635     /**
636      * Returns the maximum bytes stored in memory before content is saved to temporary files.
637      * When response content exceeds this limit, it will be written to a temporary file
638      * in the directory specified by {@link #getTempFileDirectory()}.
639      *
640      * @return the maximum bytes in memory (default: 500 * 1024)
641      * @see #setMaxInMemory(int)
642      * @see #setTempFileDirectory(File)
643      */
644     public int getMaxInMemory() {
645         return maxInMemory_;
646     }
647 
648     /**
649      * Sets the maximum bytes to have in memory, after which the content is saved to a temporary file.
650      * Set this to zero or -1 to deactivate the saving at all.
651      * @param maxInMemory maximum bytes in memory
652      */
653     public void setMaxInMemory(final int maxInMemory) {
654         maxInMemory_ = maxInMemory;
655     }
656 
657     /**
658      * Returns the maximum number of {@link Page pages} kept in {@link WebWindow#getHistory()}.
659      * @return the maximum number of pages in history
660      */
661     public int getHistorySizeLimit() {
662         return historySizeLimit_;
663     }
664 
665     /**
666      * Sets the History size limit. HtmlUnit uses SoftReferences&lt;Page&gt; for
667      * storing the pages that are part of the history. If you like to fine tune this
668      * you can use {@link #setHistoryPageCacheLimit(int)} to limit the number of page references
669      * stored by the history.
670      * @param historySizeLimit maximum number of pages in history
671      */
672     public void setHistorySizeLimit(final int historySizeLimit) {
673         historySizeLimit_ = historySizeLimit;
674     }
675 
676     /**
677      * Returns the maximum number of {@link Page pages} to cache in history.
678      * @return the maximum number of pages to cache in history
679      */
680     public int getHistoryPageCacheLimit() {
681         return historyPageCacheLimit_;
682     }
683 
684     /**
685      * Sets the maximum number of {@link Page pages} to cache in history.
686      * If this value is smaller than the {{@link #getHistorySizeLimit()} than
687      * HtmlUnit will only use soft references for the first historyPageCacheLimit
688      * entries in the history. For older entries only the url is saved; the page
689      * will be (re)retrieved on demand.
690      * @param historyPageCacheLimit maximum number of pages to cache in history
691      *        default is Integer.MAX_VALUE; negative values are having the same effect
692      *        as setting this to zero.
693      */
694     public void setHistoryPageCacheLimit(final int historyPageCacheLimit) {
695         historyPageCacheLimit_ = historyPageCacheLimit;
696     }
697 
698     /**
699      * Returns local address to be used for request execution.
700      * <p>
701      * On machines with multiple network interfaces, this parameter can be used to select the network interface
702      * from which the connection originates.
703      * <p>
704      * Default: {@code null}
705      *
706      * @return the local address
707      */
708     public InetAddress getLocalAddress() {
709         return localAddress_;
710     }
711 
712     /**
713      * Sets the local network interface address for outgoing HTTP requests.
714      * Useful on multi-homed machines to control which network interface is used.
715      *
716      * @param localAddress the local IP address to bind to, or {@code null} for automatic selection
717      */
718     public void setLocalAddress(final InetAddress localAddress) {
719         localAddress_ = localAddress;
720     }
721 
722     /**
723      * Sets whether to automatically download images by default, or not.
724      * @param downloadImages whether to automatically download images by default, or not
725      */
726     public void setDownloadImages(final boolean downloadImages) {
727         downloadImages_ = downloadImages;
728     }
729 
730     /**
731      * Returns whether to automatically download images by default, or not.
732      * @return whether to automatically download images by default, or not.
733      */
734     public boolean isDownloadImages() {
735         return downloadImages_;
736     }
737 
738     /**
739      * Sets the screen width.
740      * This value is used by JavaScript's screen.width property.
741      *
742      * @param screenWidth the screen width in pixels (must be positive)
743      */
744     public void setScreenWidth(final int screenWidth) {
745         screenWidth_ = screenWidth;
746     }
747 
748     /**
749      * Returns the screen width.
750      *
751      * @return the screen width
752      */
753     public int getScreenWidth() {
754         return screenWidth_;
755     }
756 
757     /**
758      * Sets the screen height.
759      *
760      * @param screenHeight the screen height
761      */
762     public void setScreenHeight(final int screenHeight) {
763         screenHeight_ = screenHeight;
764     }
765 
766     /**
767      * Returns the screen height.
768      *
769      * @return the screen height
770      */
771     public int getScreenHeight() {
772         return screenHeight_;
773     }
774 
775     /**
776      * Returns the Neko HTML parser reader buffer size.
777      * This controls the internal buffer size used by the NekoHTML parser
778      * for reading HTML content. Larger buffers can improve performance
779      * for large documents but consume more memory.
780      *
781      * @return the buffer size in bytes, or -1 for parser default
782      */
783     public int getNekoReaderBufferSize() {
784         return nekoReaderBufferSize_;
785     }
786 
787     /**
788      * Sets the Neko HTML parser reader buffer size.
789      * A larger buffer size can improve parsing performance for large HTML documents
790      * but will consume more memory. Set to -1 to use the parser's default buffer size.
791      *
792      * @param nekoReaderBufferSize the buffer size in bytes, or -1 for default
793      */
794     public void setNekoReaderBufferSize(final int nekoReaderBufferSize) {
795         nekoReaderBufferSize_ = nekoReaderBufferSize;
796     }
797 
798     /**
799      * Enables/disables WebSocket support. By default, this property is enabled.
800      *
801      * @param enabled {@code true} to enable WebSocket support
802      */
803     public void setWebSocketEnabled(final boolean enabled) {
804         webSocketEnabled_ = enabled;
805     }
806 
807     /**
808      * Returns {@code true} if WebSockets are enabled.
809      *
810      * @return {@code true} if WebSockets are enabled
811      */
812     public boolean isWebSocketEnabled() {
813         return webSocketEnabled_;
814     }
815 
816     /**
817      * Returns the maximum size in bytes for WebSocket text messages.
818      * Set to -1 to use the default.
819      *
820      * @return the maximum text message size in bytes, or -1 for default
821      */
822     public int getWebSocketMaxTextMessageSize() {
823         return webSocketMaxTextMessageSize_;
824     }
825 
826     /**
827      * Sets the maximum size in bytes for WebSocket text messages.
828      * This limit applies to individual text frames received by the WebSocket.
829      *
830      * @param webSocketMaxTextMessageSize the maximum size in bytes, or -1 for default
831      */
832     public void setWebSocketMaxTextMessageSize(final int webSocketMaxTextMessageSize) {
833         webSocketMaxTextMessageSize_ = webSocketMaxTextMessageSize;
834     }
835 
836     /**
837      * Returns the maximum buffer size in bytes for assembling WebSocket text messages.
838      * Set to -1 to use the default.
839      *
840      * @return the maximum text message buffer size in bytes, or -1 for default
841      */
842     public int getWebSocketMaxTextMessageBufferSize() {
843         return webSocketMaxTextMessageBufferSize_;
844     }
845 
846     /**
847      * Sets the maximum buffer size in bytes for assembling WebSocket text messages.
848      * This controls the memory used when reconstructing fragmented text messages.
849      * The buffer size should typically be larger than the maximum message size to
850      * accommodate message assembly overhead.
851      *
852      * @param webSocketMaxTextMessageBufferSize the maximum buffer size in bytes, or -1 for default
853      */
854     public void setWebSocketMaxTextMessageBufferSize(final int webSocketMaxTextMessageBufferSize) {
855         webSocketMaxTextMessageBufferSize_ = webSocketMaxTextMessageBufferSize;
856     }
857 
858     /**
859      * Returns the maximum size in bytes for WebSocket binary messages.
860      * Set to -1 to use the default.
861      *
862      * @return the maximum binary message size in bytes, or -1 for default
863      */
864     public int getWebSocketMaxBinaryMessageSize() {
865         return webSocketMaxBinaryMessageSize_;
866     }
867 
868     /**
869      * Sets the maximum size in bytes for WebSocket binary messages.
870      * This limit applies to individual binary frames received by the WebSocket.
871      *
872      * @param webSocketMaxBinaryMessageSize the maximum size in bytes, or -1 for default
873      */
874     public void setWebSocketMaxBinaryMessageSize(final int webSocketMaxBinaryMessageSize) {
875         webSocketMaxBinaryMessageSize_ = webSocketMaxBinaryMessageSize;
876     }
877 
878     /**
879      * Returns the maximum buffer size in bytes for assembling WebSocket binary messages.
880      * Set to -1 to use the container default.
881      *
882      * @return the maximum binary message buffer size in bytes, or -1 for default
883      */
884     public int getWebSocketMaxBinaryMessageBufferSize() {
885         return webSocketMaxBinaryMessageBufferSize_;
886     }
887 
888     /**
889      * Sets the maximum buffer size in bytes for assembling WebSocket binary messages.
890      * This controls the memory used when reconstructing fragmented binary messages.
891      *
892      * @param webSocketMaxBinaryMessageBufferSize the maximum buffer size in bytes, or -1 for default
893      */
894     public void setWebSocketMaxBinaryMessageBufferSize(final int webSocketMaxBinaryMessageBufferSize) {
895         webSocketMaxBinaryMessageBufferSize_ = webSocketMaxBinaryMessageBufferSize;
896     }
897 
898     /**
899      * Sets whether or not fetch polyfill should be used.
900      * @param enabled true to enable fetch polyfill
901      */
902     public void setFetchPolyfillEnabled(final boolean enabled) {
903         isFetchPolyfillEnabled_ = enabled;
904     }
905 
906     /**
907      * @return true if the fetch api polyfill is enabled
908      */
909     public boolean isFetchPolyfillEnabled() {
910         return isFetchPolyfillEnabled_;
911     }
912 
913     /**
914      * Enables/disables Geolocation support. By default, this property is disabled.
915      *
916      * @param enabled {@code true} to enable Geolocation support
917      */
918     public void setGeolocationEnabled(final boolean enabled) {
919         geolocationEnabled_ = enabled;
920     }
921 
922     /**
923      * @return {@code true} if Geolocation is enabled
924      */
925     public boolean isGeolocationEnabled() {
926         return geolocationEnabled_;
927     }
928 
929     /**
930      * @return the {@link Geolocation}
931      */
932     public Geolocation getGeolocation() {
933         return geolocation_;
934     }
935 
936     /**
937      * Sets the {@link Geolocation} to be used.
938      * @param geolocation the new location or null
939      */
940     public void setGeolocation(final Geolocation geolocation) {
941         geolocation_ = geolocation;
942     }
943 
944     /**
945      * Support class for Geolocation.
946      */
947     public static class Geolocation implements Serializable {
948         private final double accuracy_;
949         private final double latitude_;
950         private final double longitude_;
951         private final Double altitude_;
952         private final Double altitudeAccuracy_;
953         private final Double heading_;
954         private final Double speed_;
955 
956         /**
957          * Ctor.
958          *
959          * @param latitude the latitude coordinate in decimal degrees
960          * @param longitude the longitude coordinate in decimal degrees
961          * @param accuracy the accuracy of the position in meters
962          * @param altitude the altitude in meters above sea level, or null if unavailable
963          * @param altitudeAccuracy the accuracy of the altitude in meters, or null if unavailable
964          * @param heading the direction of travel in degrees (0-359), or null if unavailable
965          * @param speed the current speed in meters per second, or null if unavailable
966          */
967         public Geolocation(
968                 final double latitude,
969                 final double longitude,
970                 final double accuracy,
971                 final Double altitude,
972                 final Double altitudeAccuracy,
973                 final Double heading,
974                 final Double speed) {
975             latitude_ = latitude;
976             longitude_ = longitude;
977             accuracy_ = accuracy;
978             altitude_ = altitude;
979             altitudeAccuracy_ = altitudeAccuracy;
980             heading_ = heading;
981             speed_ = speed;
982         }
983 
984         /**
985          * @return the accuracy
986          */
987         public double getAccuracy() {
988             return accuracy_;
989         }
990 
991         /**
992          * @return the latitude
993          */
994         public double getLatitude() {
995             return latitude_;
996         }
997 
998         /**
999          * @return the longitude
1000          */
1001         public double getLongitude() {
1002             return longitude_;
1003         }
1004 
1005         /**
1006          * @return the longitude
1007          */
1008         public Double getAltitude() {
1009             return altitude_;
1010         }
1011 
1012         /**
1013          * @return the altitudeAccuracy
1014          */
1015         public Double getAltitudeAccuracy() {
1016             return altitudeAccuracy_;
1017         }
1018 
1019         /**
1020          * @return the heading
1021          */
1022         public Double getHeading() {
1023             return heading_;
1024         }
1025 
1026         /**
1027          * @return the speed
1028          */
1029         public Double getSpeed() {
1030             return speed_;
1031         }
1032     }
1033 
1034     /**
1035      * If set to {@code true}, the client will accept XMLHttpRequests to URL's
1036      * using the 'file' protocol. Allowing this introduces security problems and is
1037      * therefore not allowed by current browsers. But some browsers have special settings
1038      * to open this door; therefore we have this option also.
1039      *
1040      * <p><b>Security Warning:</b> Enabling this feature may expose local files
1041      * to web content, which can be a serious security risk.</p>
1042      *
1043      * @param fileProtocolForXMLHttpRequestsAllowed whether or not allow (local) file access
1044      */
1045     public void setFileProtocolForXMLHttpRequestsAllowed(final boolean fileProtocolForXMLHttpRequestsAllowed) {
1046         fileProtocolForXMLHttpRequestsAllowed_ = fileProtocolForXMLHttpRequestsAllowed;
1047     }
1048 
1049     /**
1050      * Indicates if the client will accept XMLHttpRequests to URL's
1051      * using the 'file' protocol.
1052      * @return {@code true} if access to local files is allowed.
1053      */
1054     public boolean isFileProtocolForXMLHttpRequestsAllowed() {
1055         return fileProtocolForXMLHttpRequestsAllowed_;
1056     }
1057 }