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