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.encoding;
16  
17  import java.util.ArrayList;
18  import java.util.Collection;
19  import java.util.List;
20  
21  import org.htmlunit.javascript.host.xml.XMLHttpRequest;
22  import org.htmlunit.util.MimeType;
23  import org.junit.jupiter.params.ParameterizedTest;
24  import org.junit.jupiter.params.provider.Arguments;
25  import org.junit.jupiter.params.provider.MethodSource;
26  import org.openqa.selenium.WebDriver;
27  
28  /**
29   * Tests for {@link XMLHttpRequest} encoding.
30   *
31   * @author Ronald Brill
32   */
33  public class XMLHttpRequestResponseTextEncodingTest extends AbstractXMLHttpRequestEncodingTest {
34  
35      /**
36       * Returns the parameterized data.
37       * @return the parameterized data
38       * @throws Exception if an error occurs
39       */
40      public static Collection<Arguments> data() throws Exception {
41          final List<Arguments> list = new ArrayList<>();
42  
43          final String[] xmlEncodingHeaders = {"", "utf8"};
44          final TestCharset[] charsetHtmlResponseHeaders =
45                  new TestCharset[] {null, TestCharset.UTF8, TestCharset.ISO88591, TestCharset.WINDOWS1250, TestCharset.GB2312};
46          final TestMimeType[] mimeTypeXmls = {TestMimeType.EMPTY, TestMimeType.XML, TestMimeType.PLAIN};
47          final TestCharset[] charsetXmlResponseHeaders =
48                  new TestCharset[] {null, TestCharset.UTF8, TestCharset.ISO88591, TestCharset.WINDOWS1250, TestCharset.GB2312};
49          final String[] boms = {null, BOM_UTF_8, BOM_UTF_16LE, BOM_UTF_16BE};
50  
51          for (final Object xmlEncodingHeader : xmlEncodingHeaders) {
52              for (final Object charsetHtmlResponseHeader : charsetHtmlResponseHeaders) {
53                  for (final Object mimeTypeXml : mimeTypeXmls) {
54                      for (final Object charsetXmlResponseHeader : charsetXmlResponseHeaders) {
55                          for (final Object bom : boms) {
56                              list.add(Arguments.of(xmlEncodingHeader,
57                                                     charsetHtmlResponseHeader,
58                                                     mimeTypeXml,
59                                                     charsetXmlResponseHeader,
60                                                     bom));
61                          }
62                      }
63                  }
64              }
65          }
66  
67          return list;
68      }
69  
70      /**
71       * The default test.
72       * @throws Exception if an error occurs
73       */
74      @ParameterizedTest(name = "_{0}_{1}_{2}_{3}_{4}")
75      @MethodSource("data")
76      void responseText(
77              final String xmlEncodingHeader,
78              final TestCharset charsetHtmlResponseHeader,
79              final TestMimeType mimeTypeXml,
80              final TestCharset charsetXmlResponseHeader,
81              final String bom) throws Exception {
82          responseText("GET", xmlEncodingHeader, charsetHtmlResponseHeader, mimeTypeXml, charsetXmlResponseHeader, bom);
83          responseText("POST", xmlEncodingHeader, charsetHtmlResponseHeader, mimeTypeXml, charsetXmlResponseHeader, bom);
84      }
85  
86      private void responseText(
87              final String httpMethod,
88              final String xmlEncodingHeader,
89              final TestCharset charsetHtmlResponseHeader,
90              final TestMimeType mimeTypeXml,
91              final TestCharset charsetXmlResponseHeader,
92              final String bom) throws Exception {
93  
94          String xmlEnc = xmlEncodingHeader;
95          if ("utf8".equals(xmlEnc)) {
96              xmlEnc = "encoding=\"utf-8\"";
97          }
98  
99          final String html = DOCTYPE_HTML
100             + "<html>\n"
101             + "  <head>\n"
102             + "    <script>\n"
103             + LOG_TEXTAREA_FUNCTION
104 
105             + "      function unicodeEscape(str) {\n"
106             + "        let result = '', index = 0, charCode, escape;\n"
107             + "        while (!isNaN(charCode = str.charCodeAt(index++))) {\n"
108             + "          escape = charCode.toString(16);\n"
109             + "          result += '\\\\u' + ('0000' + escape).slice(-4);\n"
110             + "        }\n"
111             + "        return result;\n"
112             + "      }\n"
113 
114             + "      function test() {\n"
115             + "        var request = new XMLHttpRequest();\n"
116             + "        request.open('" + httpMethod + "', '" + URL_SECOND + "', false);\n"
117             + "        request.send('');\n"
118             + "        log(unicodeEscape(request.responseText));\n"
119             + "      }\n"
120             + "    </script>\n"
121             + "  </head>\n"
122             + "  <body onload='test()'>\n"
123             + LOG_TEXTAREA
124             + "  </body>\n"
125             + "</html>";
126 
127         final String xml = "<?xml version=\"1.0\" " + xmlEnc + "?>"
128                 + "<htmlunit>"
129                 + "<c1>a</c1>"
130                 + "<c2>\u008A\u009A\u00E4\u00A9</c2>"
131                 + "<c3>\u0623\u0647\u0644\u0627\u064B</c3>"
132                 + "<c4>\u043C\u0438\u0440</c4>"
133                 + "<c5>\u623F\u95F4</c5>"
134                 + "</htmlunit>";
135 
136         String[] expected = getExpectedAlerts();
137         if (expected == null || expected.length == 0) {
138             expected = new String[] {
139                 escape("<?xml version=\"1.0\" " + xmlEnc + "?>")
140                 + "\\u003c\\u0068\\u0074\\u006d\\u006c\\u0075\\u006e\\u0069\\u0074\\u003e\\u003c\\u0063\\u0031\\u003e\\u0061\\u003c\\u002f\\u0063\\u0031\\u003e\\u003c\\u0063\\u0032\\u003e\\u0160\\u0161\\u00e4\\u00a9\\u003c\\u002f\\u0063\\u0032\\u003e\\u003c\\u0063\\u0033\\u003e\\u003f\\u003f\\u003f\\u003f\\u003f\\u003c\\u002f\\u0063\\u0033\\u003e\\u003c\\u0063\\u0034\\u003e\\u003f\\u003f\\u003f\\u003c\\u002f\\u0063\\u0034\\u003e\\u003c\\u0063\\u0035\\u003e\\u003f\\u003f\\u003c\\u002f\\u0063\\u0035\\u003e\\u003c\\u002f\\u0068\\u0074\\u006d\\u006c\\u0075\\u006e\\u0069\\u0074\\u003e"};
141 
142             if (TestCharset.UTF8.equals(charsetXmlResponseHeader) || bom != null) {
143                 expected = new String[] {
144                     escape("<?xml version=\"1.0\" " + xmlEnc + "?>")
145                     + "\\u003c\\u0068\\u0074\\u006d\\u006c\\u0075\\u006e\\u0069\\u0074\\u003e\\u003c\\u0063\\u0031\\u003e\\u0061\\u003c\\u002f\\u0063\\u0031\\u003e\\u003c\\u0063\\u0032\\u003e\\u008a\\u009a\\u00e4\\u00a9\\u003c\\u002f\\u0063\\u0032\\u003e\\u003c\\u0063\\u0033\\u003e\\u0623\\u0647\\u0644\\u0627\\u064b\\u003c\\u002f\\u0063\\u0033\\u003e\\u003c\\u0063\\u0034\\u003e\\u043c\\u0438\\u0440\\u003c\\u002f\\u0063\\u0034\\u003e\\u003c\\u0063\\u0035\\u003e\\u623f\\u95f4\\u003c\\u002f\\u0063\\u0035\\u003e\\u003c\\u002f\\u0068\\u0074\\u006d\\u006c\\u0075\\u006e\\u0069\\u0074\\u003e"};
146             }
147             else if (TestMimeType.EMPTY.equals(mimeTypeXml)) {
148                 if (TestCharset.GB2312.equals(charsetXmlResponseHeader)) {
149                     expected = new String[] {
150                         escape("<?xml version=\"1.0\" " + xmlEnc + "?>")
151                         + "\\u003c\\u0068\\u0074\\u006d\\u006c\\u0075\\u006e\\u0069\\u0074\\u003e\\u003c\\u0063\\u0031\\u003e\\u0061\\u003c\\u002f\\u0063\\u0031\\u003e\\u003c\\u0063\\u0032\\u003e\\u003f\\u003f\\u003f\\u003f\\u003c\\u002f\\u0063\\u0032\\u003e\\u003c\\u0063\\u0033\\u003e\\u003f\\u003f\\u003f\\u003f\\u003f\\u003c\\u002f\\u0063\\u0033\\u003e\\u003c\\u0063\\u0034\\u003e\\ufffd\\u07a7\\u06a7\\ufffd\\u003c\\u002f\\u0063\\u0034\\u003e\\u003c\\u0063\\u0035\\u003e\\ufffd\\ufffd\\ufffd\\ufffd\\u003c\\u002f\\u0063\\u0035\\u003e\\u003c\\u002f\\u0068\\u0074\\u006d\\u006c\\u0075\\u006e\\u0069\\u0074\\u003e"};
152                 }
153                 else if (TestCharset.WINDOWS1250.equals(charsetXmlResponseHeader)) {
154                     expected = new String[] {
155                         escape("<?xml version=\"1.0\" " + xmlEnc + "?>")
156                         + "\\u003c\\u0068\\u0074\\u006d\\u006c\\u0075\\u006e\\u0069\\u0074\\u003e\\u003c\\u0063\\u0031\\u003e\\u0061\\u003c\\u002f\\u0063\\u0031\\u003e\\u003c\\u0063\\u0032\\u003e\\u003f\\u003f\\ufffd\\u003c\\u002f\\u0063\\u0032\\u003e\\u003c\\u0063\\u0033\\u003e\\u003f\\u003f\\u003f\\u003f\\u003f\\u003c\\u002f\\u0063\\u0033\\u003e\\u003c\\u0063\\u0034\\u003e\\u003f\\u003f\\u003f\\u003c\\u002f\\u0063\\u0034\\u003e\\u003c\\u0063\\u0035\\u003e\\u003f\\u003f\\u003c\\u002f\\u0063\\u0035\\u003e\\u003c\\u002f\\u0068\\u0074\\u006d\\u006c\\u0075\\u006e\\u0069\\u0074\\u003e"};
157                 }
158                 else if (null == charsetXmlResponseHeader || TestCharset.ISO88591.equals(charsetXmlResponseHeader)) {
159                     expected = new String[] {
160                         escape("<?xml version=\"1.0\" " + xmlEnc + "?>")
161                         + "\\u003c\\u0068\\u0074\\u006d\\u006c\\u0075\\u006e\\u0069\\u0074\\u003e\\u003c\\u0063\\u0031\\u003e\\u0061\\u003c\\u002f\\u0063\\u0031\\u003e\\u003c\\u0063\\u0032\\u003e\\ufffd\\ufffd\\ufffd\\u003c\\u002f\\u0063\\u0032\\u003e\\u003c\\u0063\\u0033\\u003e\\u003f\\u003f\\u003f\\u003f\\u003f\\u003c\\u002f\\u0063\\u0033\\u003e\\u003c\\u0063\\u0034\\u003e\\u003f\\u003f\\u003f\\u003c\\u002f\\u0063\\u0034\\u003e\\u003c\\u0063\\u0035\\u003e\\u003f\\u003f\\u003c\\u002f\\u0063\\u0035\\u003e\\u003c\\u002f\\u0068\\u0074\\u006d\\u006c\\u0075\\u006e\\u0069\\u0074\\u003e"};
162                 }
163             }
164             else if (TestMimeType.PLAIN.equals(mimeTypeXml) || TestMimeType.XML.equals(mimeTypeXml)) {
165                 if (TestCharset.GB2312.equals(charsetXmlResponseHeader)) {
166                     expected = new String[] {
167                         escape("<?xml version=\"1.0\" " + xmlEnc + "?>")
168                         + "\\u003c\\u0068\\u0074\\u006d\\u006c\\u0075\\u006e\\u0069\\u0074\\u003e\\u003c\\u0063\\u0031\\u003e\\u0061\\u003c\\u002f\\u0063\\u0031\\u003e\\u003c\\u0063\\u0032\\u003e\\u003f\\u003f\\u003f\\u003f\\u003c\\u002f\\u0063\\u0032\\u003e\\u003c\\u0063\\u0033\\u003e\\u003f\\u003f\\u003f\\u003f\\u003f\\u003c\\u002f\\u0063\\u0033\\u003e\\u003c\\u0063\\u0034\\u003e\\u043c\\u0438\\u0440\\u003c\\u002f\\u0063\\u0034\\u003e\\u003c\\u0063\\u0035\\u003e\\u623f\\u95f4\\u003c\\u002f\\u0063\\u0035\\u003e\\u003c\\u002f\\u0068\\u0074\\u006d\\u006c\\u0075\\u006e\\u0069\\u0074\\u003e"};
169                 }
170                 else if (TestCharset.WINDOWS1250.equals(charsetXmlResponseHeader)) {
171                     expected = new String[] {
172                         escape("<?xml version=\"1.0\" " + xmlEnc + "?>")
173                         + "\\u003c\\u0068\\u0074\\u006d\\u006c\\u0075\\u006e\\u0069\\u0074\\u003e\\u003c\\u0063\\u0031\\u003e\\u0061\\u003c\\u002f\\u0063\\u0031\\u003e\\u003c\\u0063\\u0032\\u003e\\u003f\\u003f\\u00e4\\u00a9\\u003c\\u002f\\u0063\\u0032\\u003e\\u003c\\u0063\\u0033\\u003e\\u003f\\u003f\\u003f\\u003f\\u003f\\u003c\\u002f\\u0063\\u0033\\u003e\\u003c\\u0063\\u0034\\u003e\\u003f\\u003f\\u003f\\u003c\\u002f\\u0063\\u0034\\u003e\\u003c\\u0063\\u0035\\u003e\\u003f\\u003f\\u003c\\u002f\\u0063\\u0035\\u003e\\u003c\\u002f\\u0068\\u0074\\u006d\\u006c\\u0075\\u006e\\u0069\\u0074\\u003e"};
174                 }
175             }
176         }
177 
178         setupXmlResponse(xml, bom, mimeTypeXml, charsetXmlResponseHeader);
179         final WebDriver driver = loadPage2(html, URL_FIRST, MimeType.TEXT_HTML,
180                 charsetHtmlResponseHeader == null ? null : charsetHtmlResponseHeader.getCharset());
181 
182         verifyTextArea2(driver, expected);
183     }
184 }