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 java.io.IOException;
18  import java.io.OutputStream;
19  import java.io.OutputStreamWriter;
20  import java.io.Writer;
21  import java.util.HashMap;
22  import java.util.Map;
23  
24  import javax.servlet.Servlet;
25  import javax.servlet.http.HttpServlet;
26  import javax.servlet.http.HttpServletRequest;
27  import javax.servlet.http.HttpServletResponse;
28  
29  import org.htmlunit.html.HtmlPage;
30  import org.htmlunit.html.XHtmlPage;
31  import org.htmlunit.xml.XmlPage;
32  import org.junit.jupiter.api.Test;
33  
34  /**
35   * Tests for {@link DefaultPageCreator}.
36   *
37   * @author Marc Guillemot
38   * @author Ahmed Ashour
39   * @author Ronald Brill
40   */
41  public class DefaultPageCreatorTest extends WebServerTestCase {
42  
43      /**
44       * Verifies page types generated by various combinations of content types, doctypes and namespaces.
45       * Uses a real web server so that results can be easily verified against real browsers.
46       * @throws Exception if the test fails
47       */
48      @Test
49      public void contentTypes() throws Exception {
50          final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
51          servlets.put("/x", ContentTypeServlet.class);
52          startWebServer("./", null, servlets);
53  
54          final WebClient c = getWebClient();
55          final String base = URL_FIRST + "x?";
56  
57          assertTrue(c.getPage(base + "type=text%2Fhtml") instanceof HtmlPage);
58          assertTrue(c.getPage(base + "type=text%2Fhtml&doctype=1") instanceof HtmlPage);
59          assertTrue(c.getPage(base + "type=text%2Fhtml&ns=1") instanceof HtmlPage);
60          assertTrue(c.getPage(base + "type=text%2Fhtml&doctype=1&ns=1") instanceof HtmlPage);
61  
62          assertTrue(c.getPage(base + "type=text%2Fxhtml") instanceof TextPage);
63          assertTrue(c.getPage(base + "type=text%2Fxhtml&doctype=1") instanceof TextPage);
64          assertTrue(c.getPage(base + "type=text%2Fxhtml&ns=1") instanceof TextPage);
65          assertTrue(c.getPage(base + "type=text%2Fxhtml&doctype=1&ns=1") instanceof TextPage);
66  
67          assertTrue(c.getPage(base + "type=text%2Fxml") instanceof XmlPage);
68          assertTrue(c.getPage(base + "type=text%2Fxml&doctype=1") instanceof XmlPage);
69          assertTrue(c.getPage(base + "type=text%2Fxml&ns=1") instanceof XHtmlPage);
70          assertTrue(c.getPage(base + "type=text%2Fxml&doctype=1&ns=1") instanceof XHtmlPage);
71  
72          assertTrue(c.getPage(base + "type=application%2Fxhtml%2Bxml") instanceof XmlPage);
73          assertTrue(c.getPage(base + "type=application%2Fxhtml%2Bxml&doctype=1") instanceof XmlPage);
74          assertTrue(c.getPage(base + "type=application%2Fxhtml%2Bxml&ns=1") instanceof XHtmlPage);
75          assertTrue(c.getPage(base + "type=application%2Fxhtml%2Bxml&doctype=1&ns=1") instanceof XHtmlPage);
76      }
77  
78      /**
79       * Servlet for {@link #contentTypes()}.
80       */
81      public static class ContentTypeServlet extends HttpServlet {
82          private static final String XHTML_DOCTYPE =
83                "<!DOCTYPE html PUBLIC\n"
84              + "\"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
85              + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">";
86  
87          /** {@inheritDoc} */
88          @Override
89          protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
90              response.setContentType(request.getParameter("type"));
91              try (Writer writer = response.getWriter()) {
92                  final boolean doctype = request.getParameter("doctype") != null;
93                  if (doctype) {
94                      writer.write(XHTML_DOCTYPE);
95                  }
96                  writer.write("<html");
97                  final boolean ns = request.getParameter("ns") != null;
98                  if (ns) {
99                      writer.write(" xmlns='http://www.w3.org/1999/xhtml'");
100                 }
101                 writer.write("><body>foo</body></html>");
102             }
103         }
104     }
105 
106     /**
107      * @throws Exception if the test fails
108      */
109     @Test
110     public void noContentTypeXhtml() throws Exception {
111         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
112         servlets.put("/test", NoContentTypeXhtmlServlet.class);
113         startWebServer("./", null, servlets);
114 
115         final WebClient client = getWebClient();
116         final XHtmlPage page = client.getPage(URL_FIRST + "test");
117         assertNotNull(page);
118     }
119 
120     /**
121      * Servlet for {@link #noContentTypeLargeXhtmlHeader()}.
122      */
123     public static class NoContentTypeXhtmlServlet extends HttpServlet {
124         /** {@inheritDoc} */
125         @Override
126         protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
127             final Writer writer = response.getWriter();
128             writer.write("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n"
129                     + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
130                             + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n"
131                     + "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"lt\" lang=\"lt\">\r\n"
132                     + "<body>Hello World</body>\r\n"
133                     + "</html>");
134         }
135     }
136 
137     /**
138      * @throws Exception if the test fails
139      */
140     @Test
141     public void noContentTypeXhtmlLeadingBlank() throws Exception {
142         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
143         servlets.put("/test", NoContentTypeXhtmlLeadingBlankServlet.class);
144         startWebServer("./", null, servlets);
145 
146         final WebClient client = getWebClient();
147         final XHtmlPage page = client.getPage(URL_FIRST + "test");
148         assertNotNull(page);
149     }
150 
151     /**
152      * Servlet for {@link #noContentTypeLargeXhtmlHeader()}.
153      */
154     public static class NoContentTypeXhtmlLeadingBlankServlet extends HttpServlet {
155         /** {@inheritDoc} */
156         @Override
157         protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
158             final Writer writer = response.getWriter();
159             writer.write(" <?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n"
160                     + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
161                             + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n"
162                     + "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"lt\" lang=\"lt\">\r\n"
163                     + "<body>Hello World</body>\r\n"
164                     + "</html>");
165         }
166     }
167 
168     /**
169      * @throws Exception if the test fails
170      */
171     @Test
172     public void noContentTypeXml() throws Exception {
173         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
174         servlets.put("/test", NoContentTypeXmlServlet.class);
175         startWebServer("./", null, servlets);
176 
177         final WebClient client = getWebClient();
178         final XmlPage page = client.getPage(URL_FIRST + "test");
179         assertNotNull(page);
180     }
181 
182     /**
183      * Servlet for {@link #noContentTypeLargeXmlHeader()}.
184      */
185     public static class NoContentTypeXmlServlet extends HttpServlet {
186         /** {@inheritDoc} */
187         @Override
188         protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
189             final Writer writer = response.getWriter();
190             writer.write("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n"
191                     + "<root>Hello World</root>");
192         }
193     }
194 
195     /**
196      * @throws Exception if the test fails
197      */
198     @Test
199     public void noContentTypeXmlLeadingBlank() throws Exception {
200         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
201         servlets.put("/test", NoContentTypeXmlLeadingBlankServlet.class);
202         startWebServer("./", null, servlets);
203 
204         final WebClient client = getWebClient();
205         final XmlPage page = client.getPage(URL_FIRST + "test");
206         assertNotNull(page);
207     }
208 
209     /**
210      * Servlet for {@link #noContentTypeLargeXmlHeader()}.
211      */
212     public static class NoContentTypeXmlLeadingBlankServlet extends HttpServlet {
213         /** {@inheritDoc} */
214         @Override
215         protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
216             final Writer writer = response.getWriter();
217             writer.write(" <?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
218                     + "<root>Hello World</root>");
219         }
220     }
221 
222     /**
223      * @throws Exception if the test fails
224      */
225     @Test
226     public void noContentTypeDoctype() throws Exception {
227         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
228         servlets.put("/test", NoContentTypeDoctypeServlet.class);
229         startWebServer("./", null, servlets);
230 
231         final WebClient client = getWebClient();
232         final HtmlPage page = client.getPage(URL_FIRST + "test");
233         assertNotNull(page);
234     }
235 
236     /**
237      * Servlet for {@link #noContentTypeDoctype()}.
238      */
239     public static class NoContentTypeDoctypeServlet extends HttpServlet {
240         /** {@inheritDoc} */
241         @Override
242         protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
243             final Writer writer = response.getWriter();
244             writer.write("<!DOCTYPE HTML><body>Hello World</body>");
245         }
246     }
247 
248     /**
249      * @throws Exception if the test fails
250      */
251     @Test
252     public void noContentTypeHtml() throws Exception {
253         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
254         servlets.put("/test", NoContentTypeHtmlServlet.class);
255         startWebServer("./", null, servlets);
256 
257         final WebClient client = getWebClient();
258         final HtmlPage page = client.getPage(URL_FIRST + "test");
259         assertNotNull(page);
260     }
261 
262     /**
263      * Servlet for {@link #noContentTypeHtml()}.
264      */
265     public static class NoContentTypeHtmlServlet extends HttpServlet {
266         /** {@inheritDoc} */
267         @Override
268         protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
269             final Writer writer = response.getWriter();
270             writer.write("  <html  ><head><meta http-equiv='Content-Type' content='text/html'></head>\n"
271                 + "<body>Hello World</body></html>");
272         }
273     }
274 
275     /**
276      * @throws Exception if the test fails
277      */
278     @Test
279     public void noContentTypeHtmlStartsNotWith() throws Exception {
280         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
281         servlets.put("/test", NoContentTypeHtmlStartsNotWithServlet.class);
282         startWebServer("./", null, servlets);
283 
284         final WebClient client = getWebClient();
285         final TextPage page = client.getPage(URL_FIRST + "test");
286         assertNotNull(page);
287     }
288 
289     /**
290      * Servlet for {@link #noContentTypeHtmlStartsNotWith()}.
291      */
292     public static class NoContentTypeHtmlStartsNotWithServlet extends HttpServlet {
293         /** {@inheritDoc} */
294         @Override
295         protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
296             final Writer writer = response.getWriter();
297             writer.write("  Just to confuse the russians :-) <html><head></head><body>Hello World</body></html>");
298         }
299     }
300 
301     /**
302      * @throws Exception if the test fails
303      */
304     @Test
305     public void noContentTypeHead() throws Exception {
306         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
307         servlets.put("/test", NoContentTypeHeadServlet.class);
308         startWebServer("./", null, servlets);
309 
310         final WebClient client = getWebClient();
311         final HtmlPage page = client.getPage(URL_FIRST + "test");
312         assertNotNull(page);
313     }
314 
315     /**
316      * Servlet for {@link #noContentTypeHead()}.
317      */
318     public static class NoContentTypeHeadServlet extends HttpServlet {
319         /** {@inheritDoc} */
320         @Override
321         protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
322             final Writer writer = response.getWriter();
323             writer.write("  <head></head><body>Hello World</body>");
324         }
325     }
326 
327     /**
328      * @throws Exception if the test fails
329      */
330     @Test
331     public void noContentTypeScript() throws Exception {
332         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
333         servlets.put("/test", NoContentTypeScriptServlet.class);
334         startWebServer("./", null, servlets);
335 
336         final WebClient client = getWebClient();
337         final HtmlPage page = client.getPage(URL_FIRST + "test");
338         assertNotNull(page);
339     }
340 
341     /**
342      * Servlet for {@link #noContentTypeScript()}.
343      */
344     public static class NoContentTypeScriptServlet extends HttpServlet {
345         /** {@inheritDoc} */
346         @Override
347         protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
348             final Writer writer = response.getWriter();
349             writer.write("\n<script>");
350         }
351     }
352 
353     /**
354      * @throws Exception if the test fails
355      */
356     @Test
357     public void noContentTypeTitle() throws Exception {
358         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
359         servlets.put("/test", NoContentTypeTitleServlet.class);
360         startWebServer("./", null, servlets);
361 
362         final WebClient client = getWebClient();
363         final HtmlPage page = client.getPage(URL_FIRST + "test");
364         assertNotNull(page);
365     }
366 
367     /**
368      * Servlet for {@link #noContentTypeTitle()}.
369      */
370     public static class NoContentTypeTitleServlet extends HttpServlet {
371         /** {@inheritDoc} */
372         @Override
373         protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
374             final Writer writer = response.getWriter();
375             writer.write(DOCTYPE_HTML + "<html><head><title>\u00d3</title></head><body></body></html>");
376         }
377     }
378 
379     /**
380      * @throws Exception if the test fails
381      */
382     @Test
383     public void noContentTypeBomUtf8() throws Exception {
384         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
385         servlets.put("/test", NoContentTypeBomUtf8Servlet.class);
386         startWebServer("./", null, servlets);
387 
388         final WebClient client = getWebClient();
389         final TextPage page = client.getPage(URL_FIRST + "test");
390         assertNotNull(page);
391     }
392 
393     /**
394      * Servlet for {@link #noContentTypeBomUtf8()}.
395      */
396     public static class NoContentTypeBomUtf8Servlet extends HttpServlet {
397         /** {@inheritDoc} */
398         @Override
399         protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
400             final Writer writer = response.getWriter();
401             writer.write("\u00ef\u00bb\u00bf<html><head></head><body></body></html>");
402         }
403     }
404 
405     /**
406      * @throws Exception if the test fails
407      */
408     @Test
409     public void noContentTypeBomUtf16() throws Exception {
410         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
411         servlets.put("/test", NoContentTypeBomUtf16Servlet.class);
412         startWebServer("./", null, servlets);
413 
414         final WebClient client = getWebClient();
415         final TextPage page = client.getPage(URL_FIRST + "test");
416         assertNotNull(page);
417     }
418 
419     /**
420      * Servlet for {@link #noContentTypeBomUtf16()}.
421      */
422     public static class NoContentTypeBomUtf16Servlet extends HttpServlet {
423         /** {@inheritDoc} */
424         @Override
425         protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
426             final OutputStream output = response.getOutputStream();
427             output.write('\u00fe');
428             output.write('\u00ff');
429             output.flush();
430             final Writer writer = new OutputStreamWriter(output, "UTF16");
431             writer.write(DOCTYPE_HTML + "<html><head></head><body></body></html>");
432             writer.flush();
433         }
434     }
435 }