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 static org.eclipse.jetty.http.HttpVersion.HTTP_1_1;
18  
19  import java.io.IOException;
20  import java.net.MalformedURLException;
21  import java.net.Socket;
22  import java.net.SocketException;
23  import java.net.URL;
24  
25  import org.eclipse.jetty.server.SslConnectionFactory;
26  import org.eclipse.jetty.util.ssl.SslContextFactory;
27  import org.eclipse.jetty.util.ssl.SslContextFactory.Server;
28  import org.htmlunit.html.HtmlPage;
29  import org.junit.jupiter.api.Assertions;
30  import org.junit.jupiter.api.Assumptions;
31  import org.junit.jupiter.api.Test;
32  
33  /**
34   * Tests for SOCKS proxy support.
35   * This test {@link org.junit.Assume assumes} a SOCKS proxy to be available on port
36   * {@link WebTestCase#SOCKS_PROXY_PORT} of {@link WebTestCase#SOCKS_PROXY_HOST}.
37   *
38   * @author Marc Guillemot
39   * @author Ahmed Ashour
40   * @author Ronald Brill
41   */
42  public class SocksProxyTest extends WebServerTestCase {
43  
44      /**
45       * @throws Exception if an error occurs
46       */
47      @Test
48      public void http() throws Exception {
49          assumeSocksProxyInUse();
50          doHttpTest(getWebClientWithSocksProxy());
51      }
52  
53      /**
54       * Ensure that an error occurs if no SOCKS proxy runs on the configured port.
55       * @throws Exception if an error occurs
56       */
57      @Test
58      public void httpWithBadProxyPortShouldFail() throws Exception {
59          Assertions.assertThrows(SocketException.class, () -> doHttpTest(getWebClientWithWrongSocksProxy()));
60      }
61  
62      private static void doHttpTest(final WebClient client) throws Exception, IOException, MalformedURLException {
63          final URL http = new URL("http://localhost:" + PORT + "/");
64          final HtmlPage page = client.getPage(http);
65          assertEquals("hello", page.getTitleText());
66      }
67  
68      /**
69       * @throws Exception if an error occurs
70       */
71      @Test
72      public void https() throws Exception {
73          assumeSocksProxyInUse();
74          doHttpsTest(getWebClientWithSocksProxy());
75      }
76  
77      /**
78       * If the SOCKS proxy port is wrong, an exception should occur otherwise
79       * it shows that the proxy isn't used.
80       * @throws Exception if an error occurs
81       */
82      @Test
83      public void httpsWithBadProxyPortShouldFail() throws Exception {
84          Assertions.assertThrows(SocketException.class, () -> doHttpsTest(getWebClientWithWrongSocksProxy()));
85      }
86  
87      private void doHttpsTest(final WebClient webClient) throws Exception {
88          webClient.getOptions().setUseInsecureSSL(true);
89  
90          final URL https = new URL("https://localhost:" + PORT2 + "/");
91          loadPage("<div>test</div>", https);
92      }
93  
94      private static void assumeSocksProxyInUse() {
95          try {
96              try (Socket socket = new Socket(SOCKS_PROXY_HOST, SOCKS_PROXY_PORT)) {
97                  // nothing
98              }
99          }
100         catch (final IOException e) {
101             Assumptions.assumeTrue(false, "Socks proxy is not available");
102         }
103     }
104 
105     private WebClient getWebClientWithWrongSocksProxy() {
106         final WebClient client = getWebClient();
107         client.getOptions().setProxyConfig(new ProxyConfig(SOCKS_PROXY_HOST, SOCKS_PROXY_PORT + 1, null, true));
108         return client;
109     }
110 
111     private WebClient getWebClientWithSocksProxy() {
112         final WebClient client = getWebClient();
113         client.getOptions().setTimeout(10_000);
114         client.getOptions().setProxyConfig(new ProxyConfig(SOCKS_PROXY_HOST, SOCKS_PROXY_PORT, null, true));
115         return client;
116     }
117 
118 
119     @Override
120     protected boolean isHttps() {
121         return true;
122     }
123 
124     @Override
125     public SslConnectionFactory getSslConnectionFactory() {
126         final URL url = HttpWebConnectionInsecureSSLWithClientCertificateTest.class
127                 .getClassLoader().getResource("insecureSSL.pfx");
128 
129         final SslContextFactory contextFactory = new Server.Server();
130         contextFactory.setKeyStorePath(url.toExternalForm());
131         contextFactory.setKeyStorePassword("nopassword");
132         return new SslConnectionFactory(contextFactory, HTTP_1_1.toString());
133     }
134 }