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.junit.BrowserParameterizedRunner;
23  import org.htmlunit.junit.BrowserParameterizedRunner.Default;
24  import org.htmlunit.util.MimeType;
25  import org.junit.Test;
26  import org.junit.runner.RunWith;
27  import org.junit.runners.Parameterized.Parameter;
28  import org.junit.runners.Parameterized.Parameters;
29  import org.openqa.selenium.WebDriver;
30  
31  /**
32   * Tests for {@link XMLHttpRequest} encoding.
33   *
34   * @author Ronald Brill
35   */
36  @RunWith(BrowserParameterizedRunner.class)
37  public class XMLHttpRequestResponseXMLEncodingTest extends AbstractXMLHttpRequestEncodingTest {
38  
39      /**
40       * Returns the parameterized data.
41       * @return the parameterized data
42       * @throws Exception if an error occurs
43       */
44      @Parameters
45      public static Collection<Object[]> data() throws Exception {
46          final List<Object[]> list = new ArrayList<>();
47  
48          final String[] xmlEncodingHeaders = {"", "utf8"};
49          final TestCharset[] charsetHtmlResponseHeaders =
50                  new TestCharset[] {null, TestCharset.UTF8, TestCharset.ISO88591, TestCharset.WINDOWS1250, TestCharset.GB2312};
51          final TestMimeType[] mimeTypeXmls = {TestMimeType.EMPTY, TestMimeType.XML, TestMimeType.PLAIN};
52          final TestCharset[] charsetXmlResponseHeaders =
53                  new TestCharset[] {null, TestCharset.UTF8, TestCharset.ISO88591, TestCharset.WINDOWS1250, TestCharset.GB2312};
54          final String[] boms = {null, BOM_UTF_8, BOM_UTF_16LE, BOM_UTF_16BE};
55  
56          for (final Object xmlEncodingHeader : xmlEncodingHeaders) {
57              for (final Object charsetHtmlResponseHeader : charsetHtmlResponseHeaders) {
58                  for (final Object mimeTypeXml : mimeTypeXmls) {
59                      for (final Object charsetXmlResponseHeader : charsetXmlResponseHeaders) {
60                          for (final Object bom : boms) {
61                              list.add(new Object[] {xmlEncodingHeader,
62                                                     charsetHtmlResponseHeader,
63                                                     mimeTypeXml,
64                                                     charsetXmlResponseHeader,
65                                                     bom});
66                          }
67                      }
68                  }
69              }
70          }
71  
72          return list;
73      }
74  
75      /**
76       * The xmlEncodingHeader.
77       */
78      @Parameter
79      public String xmlEncodingHeader_;
80  
81      /**
82       * The charsetHtmlResponseHeader.
83       */
84      @Parameter(1)
85      public TestCharset charsetHtmlResponseHeader_;
86  
87      /**
88       * The charsetHtmlResponseHeader.
89       */
90      @Parameter(2)
91      public TestMimeType mimeTypeXml_;
92  
93      /**
94       * The charsetXmlResponseHeader.
95       */
96      @Parameter(3)
97      public TestCharset charsetXmlResponseHeader_;
98  
99      /**
100      * The charsetXmlResponseHeader.
101      */
102     @Parameter(4)
103     public String bom_;
104 
105     /**
106      * The default test.
107      * @throws Exception if an error occurs
108      */
109     @Test
110     @Default
111     public void responseText() throws Exception {
112         responseText(xmlEncodingHeader_, charsetHtmlResponseHeader_, mimeTypeXml_, charsetXmlResponseHeader_, bom_);
113     }
114 
115     private void responseText(
116            final String xmlEncodingHeader,
117             final TestCharset charsetHtmlResponseHeader,
118             final TestMimeType mimeTypeXml,
119             final TestCharset charsetXmlResponseHeader,
120             final String bom) throws Exception {
121         responseText("GET", xmlEncodingHeader, charsetHtmlResponseHeader, mimeTypeXml, charsetXmlResponseHeader, bom);
122         responseText("POST", xmlEncodingHeader, charsetHtmlResponseHeader, mimeTypeXml, charsetXmlResponseHeader, bom);
123     }
124 
125     private void responseText(
126             final String httpMethod,
127             final String xmlEncodingHeader,
128             final TestCharset charsetHtmlResponseHeader,
129             final TestMimeType mimeTypeXml,
130             final TestCharset charsetXmlResponseHeader,
131             final String bom) throws Exception {
132 
133         String xmlEnc = xmlEncodingHeader;
134         if ("utf8".equals(xmlEnc)) {
135             xmlEnc = "encoding=\"utf-8\"";
136         }
137 
138         final String html = DOCTYPE_HTML
139             + "<html>\n"
140             + "  <head>\n"
141             + "    <script>\n"
142             + LOG_TEXTAREA_FUNCTION
143 
144             + "      function unicodeEscape(str) {\n"
145             + "        let result = '', index = 0, charCode, escape;\n"
146             + "        while (!isNaN(charCode = str.charCodeAt(index++))) {\n"
147             + "          escape = charCode.toString(16);\n"
148             + "          result += '\\\\u' + ('0000' + escape).slice(-4);\n"
149             + "        }\n"
150             + "        return result;\n"
151             + "      }\n"
152 
153             + "      function test() {\n"
154             + "        var request = new XMLHttpRequest();\n"
155             + "        request.open('" + httpMethod + "', '" + URL_SECOND + "', false);\n"
156             + "        request.send('');\n"
157             + "        let xml = request.responseXML;\n"
158             + "        if (xml== null) { log('null'); return; }\n"
159 
160             + "        log(unicodeEscape(xml.getElementsByTagName('c1')[0].childNodes[0].nodeValue));\n"
161             + "        log(unicodeEscape(xml.getElementsByTagName('c2')[0].childNodes[0].nodeValue));\n"
162             + "        log(unicodeEscape(xml.getElementsByTagName('c3')[0].childNodes[0].nodeValue));\n"
163             + "        log(unicodeEscape(xml.getElementsByTagName('c4')[0].childNodes[0].nodeValue));\n"
164             + "        log(unicodeEscape(xml.getElementsByTagName('c5')[0].childNodes[0].nodeValue));\n"
165             + "      }\n"
166             + "    </script>\n"
167             + "  </head>\n"
168             + "  <body onload='test()'>\n"
169             + LOG_TEXTAREA
170             + "  </body>\n"
171             + "</html>";
172 
173         final String xml = "<?xml version=\"1.0\" " + xmlEnc + "?>"
174                 + "<htmlunit>"
175                 + "<c1>a</c1>"
176                 + "<c2>\u008A\u009A\u00E4\u00A9</c2>"
177                 + "<c3>\u0623\u0647\u0644\u0627\u064B</c3>"
178                 + "<c4>\u043C\u0438\u0440</c4>"
179                 + "<c5>\u623F\u95F4</c5>"
180                 + "</htmlunit>";
181 
182         String[] expected = getExpectedAlerts();
183         if (expected == null || expected.length == 0) {
184             expected = new String[] {"\\u0061", "\\u0160\\u0161\\u00e4\\u00a9", "\\u003f\\u003f\\u003f\\u003f\\u003f", "\\u003f\\u003f\\u003f", "\\u003f\\u003f"};
185 
186             if (TestMimeType.PLAIN.equals(mimeTypeXml)) {
187                 expected = new String[] {"null"};
188             }
189             else if (TestCharset.UTF8.equals(charsetXmlResponseHeader) || bom != null) {
190                 expected = new String[] {"\\u0061", "\\u008a\\u009a\\u00e4\\u00a9", "\\u0623\\u0647\\u0644\\u0627\\u064b", "\\u043c\\u0438\\u0440", "\\u623f\\u95f4"};
191             }
192             else if (TestMimeType.EMPTY.equals(mimeTypeXml)) {
193                 /* real FF - ignored for the moment
194                 if (getBrowserVersion().isFirefox()
195                         && !TestCharset.UTF8.equals(charsetXmlResponseHeader)) {
196                     expected = new String[] {"null"};
197                 }
198                 else */
199                 if (TestCharset.GB2312.equals(charsetXmlResponseHeader)) {
200                     expected = new String[] {"\\u0061", "\\u003f\\u003f\\u003f\\u003f", "\\u003f\\u003f\\u003f\\u003f\\u003f", "\\ufffd\\u07a7\\u06a7\\ufffd", "\\ufffd\\ufffd\\ufffd\\ufffd"};
201                 }
202                 else if (TestCharset.WINDOWS1250.equals(charsetXmlResponseHeader)) {
203                     expected = new String[] {"\\u0061", "\\u003f\\u003f\\ufffd", "\\u003f\\u003f\\u003f\\u003f\\u003f", "\\u003f\\u003f\\u003f", "\\u003f\\u003f"};
204                 }
205                 else if (null == charsetXmlResponseHeader || TestCharset.ISO88591.equals(charsetXmlResponseHeader)) {
206                     expected = new String[] {"\\u0061", "\\ufffd\\ufffd\\ufffd", "\\u003f\\u003f\\u003f\\u003f\\u003f", "\\u003f\\u003f\\u003f", "\\u003f\\u003f"};
207                 }
208             }
209             else if (TestMimeType.XML.equals(mimeTypeXml)) {
210                 if (TestCharset.GB2312.equals(charsetXmlResponseHeader)) {
211                     expected = new String[] {"\\u0061", "\\u003f\\u003f\\u003f\\u003f", "\\u003f\\u003f\\u003f\\u003f\\u003f", "\\u043c\\u0438\\u0440", "\\u623f\\u95f4"};
212                 }
213                 else if (TestCharset.WINDOWS1250.equals(charsetXmlResponseHeader)) {
214                     expected = new String[] {"\\u0061", "\\u003f\\u003f\\u00e4\\u00a9", "\\u003f\\u003f\\u003f\\u003f\\u003f", "\\u003f\\u003f\\u003f", "\\u003f\\u003f"};
215                 }
216             }
217         }
218 
219         setupXmlResponse(xml, bom, mimeTypeXml, charsetXmlResponseHeader);
220         final WebDriver driver = loadPage2(html, URL_FIRST, MimeType.TEXT_HTML,
221                 charsetHtmlResponseHeader == null ? null : charsetHtmlResponseHeader.getCharset());
222 
223         verifyTextArea2(driver, expected);
224     }
225 }