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 java.nio.charset.StandardCharsets.ISO_8859_1;
18  import static java.nio.charset.StandardCharsets.UTF_8;
19  
20  import java.io.ByteArrayOutputStream;
21  import java.io.IOException;
22  import java.io.OutputStream;
23  import java.io.Writer;
24  import java.nio.charset.Charset;
25  import java.util.ArrayList;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.zip.GZIPOutputStream;
30  
31  import javax.servlet.Servlet;
32  import javax.servlet.http.HttpServlet;
33  import javax.servlet.http.HttpServletRequest;
34  import javax.servlet.http.HttpServletResponse;
35  
36  import org.htmlunit.html.HtmlPage;
37  import org.htmlunit.http.HttpStatus;
38  import org.htmlunit.util.MimeType;
39  import org.htmlunit.util.NameValuePair;
40  import org.junit.jupiter.api.AfterEach;
41  import org.junit.jupiter.api.Test;
42  
43  /**
44   * Tests for {@link WebResponse}.
45   *
46   * @author Marc Guillemot
47   * @author Ahmed Ashour
48   * @author Ronald Brill
49   * @author Lai Quang Duong
50   */
51  public class WebResponseTest extends WebServerTestCase {
52  
53      /**
54       * @throws Exception if the test fails
55       */
56      @Test
57      public void encodingCharsetUtf8() throws Exception {
58          final String title = "\u6211\u662F\u6211\u7684FOCUS";
59          final String content = DOCTYPE_HTML
60              + "<html><head>\n"
61              + "<title>" + title + "</title>\n"
62              + "</head>\n"
63              + "<body>\n"
64              + "</body></html>";
65  
66          final WebClient client = getWebClient();
67  
68          final MockWebConnection webConnection = new MockWebConnection();
69          webConnection.setResponse(URL_FIRST, content.getBytes(UTF_8), 200, "OK", "text/html; charset=UTF-8", null);
70          client.setWebConnection(webConnection);
71          final WebRequest request = new WebRequest(URL_FIRST);
72          request.setCharset(UTF_8);
73          final HtmlPage page = client.getPage(request);
74          assertEquals(title, page.getTitleText());
75  
76          assertEquals(content, page.getWebResponse().getContentAsString());
77          assertEquals(content, page.getWebResponse().getContentAsString(UTF_8));
78      }
79  
80      /**
81       * @throws Exception if the test fails
82       */
83      @Test
84      public void quotedCharset() throws Exception {
85          final String xml
86              = "<books id='myId'>\n"
87              + "  <book>\n"
88              + "    <title>Immortality</title>\n"
89              + "    <author>John Smith</author>\n"
90              + "  </book>\n"
91              + "</books>";
92  
93          final List<String> collectedAlerts = new ArrayList<>();
94          final WebClient client = getWebClient();
95          client.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
96          final MockWebConnection conn = new MockWebConnection();
97          conn.setResponse(URL_FIRST, xml, HttpStatus.OK_200, HttpStatus.OK_200_MSG,
98                  "text/xml; charset=\"ISO-8859-1\"", null);
99          client.setWebConnection(conn);
100         client.getPage(URL_FIRST);
101     }
102 
103     /**
104      * Test that extracting charset from Content-Type header is forgiving.
105      * @throws Exception if the test fails
106      */
107     @Test
108     public void illegalCharset() throws Exception {
109         illegalCharset("text/html; text/html; charset=ISO-8859-1;", Charset.forName("windows-1252"));
110         illegalCharset("text/html; charset=UTF-8; charset=UTF-8", UTF_8);
111         illegalCharset("text/html; charset=#sda+s", ISO_8859_1);
112         illegalCharset("text/html; charset=UnknownCharset", ISO_8859_1);
113     }
114 
115     private void illegalCharset(final String cntTypeHeader, final Charset expectedCharset) throws Exception {
116         final MockWebConnection conn = new MockWebConnection();
117         final List<NameValuePair> headers = new ArrayList<>();
118         headers.add(new NameValuePair(HttpHeader.CONTENT_TYPE, cntTypeHeader));
119         conn.setDefaultResponse("<html/>", 200, "OK", MimeType.TEXT_HTML, headers);
120         final WebClient webClient = getWebClient();
121         webClient.setWebConnection(conn);
122 
123         final Page page = webClient.getPage(URL_FIRST);
124         assertEquals(expectedCharset, page.getWebResponse().getContentCharset());
125         assertEquals(cntTypeHeader, page.getWebResponse().getResponseHeaderValue(HttpHeader.CONTENT_TYPE));
126         assertEquals("<html/>", page.getWebResponse().getContentAsString());
127     }
128 
129     /**
130      * @throws Exception if the test fails
131      */
132     @Test
133     public void responseHeaders() throws Exception {
134         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
135         servlets.put("/test", ResponseHeadersServlet.class);
136         startWebServer("./", null, servlets);
137         final WebClient client = getWebClient();
138         final HtmlPage page = client.getPage(URL_FIRST + "test");
139         assertEquals("some_value", page.getWebResponse().getResponseHeaderValue("some_header"));
140     }
141 
142     /**
143      * Servlet for {@link #responseHeaders()}.
144      */
145     public static class ResponseHeadersServlet extends HttpServlet {
146         /**
147          * {@inheritDoc}
148          */
149         @Override
150         protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
151             response.setContentType(MimeType.TEXT_HTML);
152             response.setHeader("some_header", "some_value");
153             final Writer writer = response.getWriter();
154             writer.write("<html/>");
155         }
156     }
157 
158     /**
159      * @throws Exception if the test fails
160      */
161     @Test
162     public void getContentAsStringIllegalCharset() throws Exception {
163         final MockWebConnection conn = new MockWebConnection();
164         final List<NameValuePair> headers = new ArrayList<>();
165         conn.setDefaultResponse("<html/>", 200, "OK", MimeType.TEXT_HTML, headers);
166         final WebClient webClient = getWebClient();
167         webClient.setWebConnection(conn);
168 
169         final Page page = webClient.getPage(URL_FIRST);
170         final WebResponse webResponse = page.getWebResponse();
171         assertEquals("<html/>", webResponse.getContentAsString(webResponse.getContentCharset()));
172     }
173 
174     /**
175      * Servlet for {@link #binaryResponseHeaders()}.
176      */
177     public static class BinaryResponseHeadersServlet extends HttpServlet {
178         private static final String RESPONSE = DOCTYPE_HTML
179                 + "<html><head><title>Foo</title></head><body>This is foo!</body></html>";
180 
181         /**
182          * {@inheritDoc}
183          */
184         @Override
185         protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
186             final byte[] bytes = RESPONSE.getBytes(UTF_8);
187             final ByteArrayOutputStream bos = new ByteArrayOutputStream();
188             final GZIPOutputStream gout = new GZIPOutputStream(bos);
189             gout.write(bytes);
190             gout.finish();
191 
192             final byte[] encoded = bos.toByteArray();
193 
194             response.setContentType(MimeType.TEXT_HTML);
195             response.setCharacterEncoding(UTF_8.name());
196             response.setStatus(200);
197             response.setContentLength(encoded.length);
198             response.setHeader("Content-Encoding", "gzip");
199 
200             final OutputStream rout = response.getOutputStream();
201             rout.write(encoded);
202         }
203     }
204 
205     /**
206      * @throws Exception if the test fails
207      */
208     @Test
209     public void binaryResponseHeaders() throws Exception {
210         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
211         servlets.put("/test", BinaryResponseHeadersServlet.class);
212         startWebServer("./", null, servlets);
213 
214         final HtmlPage page = getWebClient().getPage(URL_FIRST + "test");
215         assertEquals(BinaryResponseHeadersServlet.RESPONSE,
216                 page.getWebResponse().getContentAsString(UTF_8));
217 
218         assertEquals("gzip", page.getWebResponse().getResponseHeaderValue("Content-Encoding"));
219         assertEquals("85", page.getWebResponse().getResponseHeaderValue(HttpHeader.CONTENT_LENGTH));
220     }
221 
222     /**
223      * Stop the WebServer.
224      * @throws Exception if it fails
225      */
226     @AfterEach
227     public void stopServer() throws Exception {
228         stopWebServer();
229     }
230 }