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