xref: /freebsd/contrib/expat/tests/ns_tests.c (revision 4543ef516683042d46f3bd3bb8a4f3f746e00499)
1 /* Tests in the "namespace" test case for the Expat test suite
2                             __  __            _
3                          ___\ \/ /_ __   __ _| |_
4                         / _ \\  /| '_ \ / _` | __|
5                        |  __//  \| |_) | (_| | |_
6                         \___/_/\_\ .__/ \__,_|\__|
7                                  |_| XML parser
8 
9    Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
10    Copyright (c) 2003      Greg Stein <gstein@users.sourceforge.net>
11    Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
12    Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
13    Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
14    Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
15    Copyright (c) 2017      Joe Orton <jorton@redhat.com>
16    Copyright (c) 2017      José Gutiérrez de la Concha <jose@zeroc.com>
17    Copyright (c) 2018      Marco Maggi <marco.maggi-ipsu@poste.it>
18    Copyright (c) 2019      David Loffredo <loffredo@steptools.com>
19    Copyright (c) 2020      Tim Gates <tim.gates@iress.com>
20    Copyright (c) 2021      Donghee Na <donghee.na@python.org>
21    Copyright (c) 2023      Sony Corporation / Snild Dolkow <snild@sony.com>
22    Licensed under the MIT license:
23 
24    Permission is  hereby granted,  free of charge,  to any  person obtaining
25    a  copy  of  this  software   and  associated  documentation  files  (the
26    "Software"),  to  deal in  the  Software  without restriction,  including
27    without  limitation the  rights  to use,  copy,  modify, merge,  publish,
28    distribute, sublicense, and/or sell copies of the Software, and to permit
29    persons  to whom  the Software  is  furnished to  do so,  subject to  the
30    following conditions:
31 
32    The above copyright  notice and this permission notice  shall be included
33    in all copies or substantial portions of the Software.
34 
35    THE  SOFTWARE  IS  PROVIDED  "AS  IS",  WITHOUT  WARRANTY  OF  ANY  KIND,
36    EXPRESS  OR IMPLIED,  INCLUDING  BUT  NOT LIMITED  TO  THE WARRANTIES  OF
37    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
38    NO EVENT SHALL THE AUTHORS OR  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
39    DAMAGES OR  OTHER LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT,  TORT OR
40    OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
41    USE OR OTHER DEALINGS IN THE SOFTWARE.
42 */
43 
44 #include "expat_config.h"
45 
46 #include <string.h>
47 
48 #include "expat.h"
49 #include "internal.h"
50 #include "minicheck.h"
51 #include "common.h"
52 #include "dummy.h"
53 #include "handlers.h"
54 #include "ns_tests.h"
55 
56 static void
namespace_setup(void)57 namespace_setup(void) {
58   g_parser = XML_ParserCreateNS(NULL, XCS(' '));
59   if (g_parser == NULL)
60     fail("Parser not created.");
61 }
62 
63 static void
namespace_teardown(void)64 namespace_teardown(void) {
65   basic_teardown();
66 }
67 
START_TEST(test_return_ns_triplet)68 START_TEST(test_return_ns_triplet) {
69   const char *text = "<foo:e xmlns:foo='http://example.org/' bar:a='12'\n"
70                      "       xmlns:bar='http://example.org/'>";
71   const char *epilog = "</foo:e>";
72   const XML_Char *elemstr[]
73       = {XCS("http://example.org/ e foo"), XCS("http://example.org/ a bar")};
74   XML_SetReturnNSTriplet(g_parser, XML_TRUE);
75   XML_SetUserData(g_parser, (void *)elemstr);
76   XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
77   XML_SetNamespaceDeclHandler(g_parser, dummy_start_namespace_decl_handler,
78                               dummy_end_namespace_decl_handler);
79   g_triplet_start_flag = XML_FALSE;
80   g_triplet_end_flag = XML_FALSE;
81   init_dummy_handlers();
82   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
83       == XML_STATUS_ERROR)
84     xml_failure(g_parser);
85   /* Check that unsetting "return triplets" fails while still parsing */
86   XML_SetReturnNSTriplet(g_parser, XML_FALSE);
87   if (_XML_Parse_SINGLE_BYTES(g_parser, epilog, (int)strlen(epilog), XML_TRUE)
88       == XML_STATUS_ERROR)
89     xml_failure(g_parser);
90   if (! g_triplet_start_flag)
91     fail("triplet_start_checker not invoked");
92   if (! g_triplet_end_flag)
93     fail("triplet_end_checker not invoked");
94   if (get_dummy_handler_flags()
95       != (DUMMY_START_NS_DECL_HANDLER_FLAG | DUMMY_END_NS_DECL_HANDLER_FLAG))
96     fail("Namespace handlers not called");
97 }
98 END_TEST
99 
100 /* Test that the parsing status is correctly reset by XML_ParserReset().
101  * We use test_return_ns_triplet() for our example parse to improve
102  * coverage of tidying up code executed.
103  */
START_TEST(test_ns_parser_reset)104 START_TEST(test_ns_parser_reset) {
105   XML_ParsingStatus status;
106 
107   XML_GetParsingStatus(g_parser, &status);
108   if (status.parsing != XML_INITIALIZED)
109     fail("parsing status doesn't start INITIALIZED");
110   test_return_ns_triplet();
111   XML_GetParsingStatus(g_parser, &status);
112   if (status.parsing != XML_FINISHED)
113     fail("parsing status doesn't end FINISHED");
114   XML_ParserReset(g_parser, NULL);
115   XML_GetParsingStatus(g_parser, &status);
116   if (status.parsing != XML_INITIALIZED)
117     fail("parsing status doesn't reset to INITIALIZED");
118 }
119 END_TEST
120 
121 static void
run_ns_tagname_overwrite_test(const char * text,const XML_Char * result)122 run_ns_tagname_overwrite_test(const char *text, const XML_Char *result) {
123   CharData storage;
124   CharData_Init(&storage);
125   XML_SetUserData(g_parser, &storage);
126   XML_SetElementHandler(g_parser, overwrite_start_checker,
127                         overwrite_end_checker);
128   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
129       == XML_STATUS_ERROR)
130     xml_failure(g_parser);
131   CharData_CheckXMLChars(&storage, result);
132 }
133 
134 /* Regression test for SF bug #566334. */
START_TEST(test_ns_tagname_overwrite)135 START_TEST(test_ns_tagname_overwrite) {
136   const char *text = "<n:e xmlns:n='http://example.org/'>\n"
137                      "  <n:f n:attr='foo'/>\n"
138                      "  <n:g n:attr2='bar'/>\n"
139                      "</n:e>";
140   const XML_Char *result = XCS("start http://example.org/ e\n")
141       XCS("start http://example.org/ f\n")
142           XCS("attribute http://example.org/ attr\n")
143               XCS("end http://example.org/ f\n")
144                   XCS("start http://example.org/ g\n")
145                       XCS("attribute http://example.org/ attr2\n")
146                           XCS("end http://example.org/ g\n")
147                               XCS("end http://example.org/ e\n");
148   run_ns_tagname_overwrite_test(text, result);
149 }
150 END_TEST
151 
152 /* Regression test for SF bug #566334. */
START_TEST(test_ns_tagname_overwrite_triplet)153 START_TEST(test_ns_tagname_overwrite_triplet) {
154   const char *text = "<n:e xmlns:n='http://example.org/'>\n"
155                      "  <n:f n:attr='foo'/>\n"
156                      "  <n:g n:attr2='bar'/>\n"
157                      "</n:e>";
158   const XML_Char *result = XCS("start http://example.org/ e n\n")
159       XCS("start http://example.org/ f n\n")
160           XCS("attribute http://example.org/ attr n\n")
161               XCS("end http://example.org/ f n\n")
162                   XCS("start http://example.org/ g n\n")
163                       XCS("attribute http://example.org/ attr2 n\n")
164                           XCS("end http://example.org/ g n\n")
165                               XCS("end http://example.org/ e n\n");
166   XML_SetReturnNSTriplet(g_parser, XML_TRUE);
167   run_ns_tagname_overwrite_test(text, result);
168 }
169 END_TEST
170 
171 /* Regression test for SF bug #620343. */
START_TEST(test_start_ns_clears_start_element)172 START_TEST(test_start_ns_clears_start_element) {
173   /* This needs to use separate start/end tags; using the empty tag
174      syntax doesn't cause the problematic path through Expat to be
175      taken.
176   */
177   const char *text = "<e xmlns='http://example.org/'></e>";
178 
179   XML_SetStartElementHandler(g_parser, start_element_fail);
180   XML_SetStartNamespaceDeclHandler(g_parser, start_ns_clearing_start_element);
181   XML_SetEndNamespaceDeclHandler(g_parser, dummy_end_namespace_decl_handler);
182   XML_UseParserAsHandlerArg(g_parser);
183   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
184       == XML_STATUS_ERROR)
185     xml_failure(g_parser);
186 }
187 END_TEST
188 
189 /* Regression test for SF bug #616863. */
START_TEST(test_default_ns_from_ext_subset_and_ext_ge)190 START_TEST(test_default_ns_from_ext_subset_and_ext_ge) {
191   const char *text = "<?xml version='1.0'?>\n"
192                      "<!DOCTYPE doc SYSTEM 'http://example.org/doc.dtd' [\n"
193                      "  <!ENTITY en SYSTEM 'http://example.org/entity.ent'>\n"
194                      "]>\n"
195                      "<doc xmlns='http://example.org/ns1'>\n"
196                      "&en;\n"
197                      "</doc>";
198 
199   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
200   XML_SetExternalEntityRefHandler(g_parser, external_entity_handler);
201   /* We actually need to set this handler to tickle this bug. */
202   XML_SetStartElementHandler(g_parser, dummy_start_element);
203   XML_SetUserData(g_parser, NULL);
204   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
205       == XML_STATUS_ERROR)
206     xml_failure(g_parser);
207 }
208 END_TEST
209 
210 /* Regression test #1 for SF bug #673791. */
START_TEST(test_ns_prefix_with_empty_uri_1)211 START_TEST(test_ns_prefix_with_empty_uri_1) {
212   const char *text = "<doc xmlns:prefix='http://example.org/'>\n"
213                      "  <e xmlns:prefix=''/>\n"
214                      "</doc>";
215 
216   expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
217                  "Did not report re-setting namespace"
218                  " URI with prefix to ''.");
219 }
220 END_TEST
221 
222 /* Regression test #2 for SF bug #673791. */
START_TEST(test_ns_prefix_with_empty_uri_2)223 START_TEST(test_ns_prefix_with_empty_uri_2) {
224   const char *text = "<?xml version='1.0'?>\n"
225                      "<docelem xmlns:pre=''/>";
226 
227   expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
228                  "Did not report setting namespace URI with prefix to ''.");
229 }
230 END_TEST
231 
232 /* Regression test #3 for SF bug #673791. */
START_TEST(test_ns_prefix_with_empty_uri_3)233 START_TEST(test_ns_prefix_with_empty_uri_3) {
234   const char *text = "<!DOCTYPE doc [\n"
235                      "  <!ELEMENT doc EMPTY>\n"
236                      "  <!ATTLIST doc\n"
237                      "    xmlns:prefix CDATA ''>\n"
238                      "]>\n"
239                      "<doc/>";
240 
241   expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
242                  "Didn't report attr default setting NS w/ prefix to ''.");
243 }
244 END_TEST
245 
246 /* Regression test #4 for SF bug #673791. */
START_TEST(test_ns_prefix_with_empty_uri_4)247 START_TEST(test_ns_prefix_with_empty_uri_4) {
248   const char *text = "<!DOCTYPE doc [\n"
249                      "  <!ELEMENT prefix:doc EMPTY>\n"
250                      "  <!ATTLIST prefix:doc\n"
251                      "    xmlns:prefix CDATA 'http://example.org/'>\n"
252                      "]>\n"
253                      "<prefix:doc/>";
254   /* Packaged info expected by the end element handler;
255      the weird structuring lets us reuse the triplet_end_checker()
256      function also used for another test. */
257   const XML_Char *elemstr[] = {XCS("http://example.org/ doc prefix")};
258   XML_SetReturnNSTriplet(g_parser, XML_TRUE);
259   XML_SetUserData(g_parser, (void *)elemstr);
260   XML_SetEndElementHandler(g_parser, triplet_end_checker);
261   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
262       == XML_STATUS_ERROR)
263     xml_failure(g_parser);
264 }
265 END_TEST
266 
267 /* Test with non-xmlns prefix */
START_TEST(test_ns_unbound_prefix)268 START_TEST(test_ns_unbound_prefix) {
269   const char *text = "<!DOCTYPE doc [\n"
270                      "  <!ELEMENT prefix:doc EMPTY>\n"
271                      "  <!ATTLIST prefix:doc\n"
272                      "    notxmlns:prefix CDATA 'http://example.org/'>\n"
273                      "]>\n"
274                      "<prefix:doc/>";
275 
276   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
277       != XML_STATUS_ERROR)
278     fail("Unbound prefix incorrectly passed");
279   if (XML_GetErrorCode(g_parser) != XML_ERROR_UNBOUND_PREFIX)
280     xml_failure(g_parser);
281 }
282 END_TEST
283 
START_TEST(test_ns_default_with_empty_uri)284 START_TEST(test_ns_default_with_empty_uri) {
285   const char *text = "<doc xmlns='http://example.org/'>\n"
286                      "  <e xmlns=''/>\n"
287                      "</doc>";
288   /* Add some handlers to exercise extra code paths */
289   XML_SetStartNamespaceDeclHandler(g_parser,
290                                    dummy_start_namespace_decl_handler);
291   XML_SetEndNamespaceDeclHandler(g_parser, dummy_end_namespace_decl_handler);
292   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
293       == XML_STATUS_ERROR)
294     xml_failure(g_parser);
295 }
296 END_TEST
297 
298 /* Regression test for SF bug #692964: two prefixes for one namespace. */
START_TEST(test_ns_duplicate_attrs_diff_prefixes)299 START_TEST(test_ns_duplicate_attrs_diff_prefixes) {
300   const char *text = "<doc xmlns:a='http://example.org/a'\n"
301                      "     xmlns:b='http://example.org/a'\n"
302                      "     a:a='v' b:a='v' />";
303   expect_failure(text, XML_ERROR_DUPLICATE_ATTRIBUTE,
304                  "did not report multiple attributes with same URI+name");
305 }
306 END_TEST
307 
START_TEST(test_ns_duplicate_hashes)308 START_TEST(test_ns_duplicate_hashes) {
309   /* The hash of an attribute is calculated as the hash of its URI
310    * concatenated with a space followed by its name (after the
311    * colon).  We wish to generate attributes with the same hash
312    * value modulo the attribute table size so that we can check that
313    * the attribute hash table works correctly.  The attribute hash
314    * table size will be the smallest power of two greater than the
315    * number of attributes, but at least eight.  There is
316    * unfortunately no programmatic way of getting the hash or the
317    * table size at user level, but the test code coverage percentage
318    * will drop if the hashes cease to point to the same row.
319    *
320    * The cunning plan is to have few enough attributes to have a
321    * reliable table size of 8, and have the single letter attribute
322    * names be 8 characters apart, producing a hash which will be the
323    * same modulo 8.
324    */
325   const char *text = "<doc xmlns:a='http://example.org/a'\n"
326                      "     a:a='v' a:i='w' />";
327   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
328       == XML_STATUS_ERROR)
329     xml_failure(g_parser);
330 }
331 END_TEST
332 
333 /* Regression test for SF bug #695401: unbound prefix. */
START_TEST(test_ns_unbound_prefix_on_attribute)334 START_TEST(test_ns_unbound_prefix_on_attribute) {
335   const char *text = "<doc a:attr=''/>";
336   expect_failure(text, XML_ERROR_UNBOUND_PREFIX,
337                  "did not report unbound prefix on attribute");
338 }
339 END_TEST
340 
341 /* Regression test for SF bug #695401: unbound prefix. */
START_TEST(test_ns_unbound_prefix_on_element)342 START_TEST(test_ns_unbound_prefix_on_element) {
343   const char *text = "<a:doc/>";
344   expect_failure(text, XML_ERROR_UNBOUND_PREFIX,
345                  "did not report unbound prefix on element");
346 }
347 END_TEST
348 
349 /* Test that long element names with namespaces are handled correctly */
START_TEST(test_ns_long_element)350 START_TEST(test_ns_long_element) {
351   const char *text
352       = "<foo:thisisalongenoughelementnametotriggerareallocation\n"
353         " xmlns:foo='http://example.org/' bar:a='12'\n"
354         " xmlns:bar='http://example.org/'>"
355         "</foo:thisisalongenoughelementnametotriggerareallocation>";
356   const XML_Char *elemstr[]
357       = {XCS("http://example.org/")
358              XCS(" thisisalongenoughelementnametotriggerareallocation foo"),
359          XCS("http://example.org/ a bar")};
360 
361   XML_SetReturnNSTriplet(g_parser, XML_TRUE);
362   XML_SetUserData(g_parser, (void *)elemstr);
363   XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
364   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
365       == XML_STATUS_ERROR)
366     xml_failure(g_parser);
367 }
368 END_TEST
369 
370 /* Test mixed population of prefixed and unprefixed attributes */
START_TEST(test_ns_mixed_prefix_atts)371 START_TEST(test_ns_mixed_prefix_atts) {
372   const char *text = "<e a='12' bar:b='13'\n"
373                      " xmlns:bar='http://example.org/'>"
374                      "</e>";
375 
376   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
377       == XML_STATUS_ERROR)
378     xml_failure(g_parser);
379 }
380 END_TEST
381 
382 /* Test having a long namespaced element name inside a short one.
383  * This exercises some internal buffer reallocation that is shared
384  * across elements with the same namespace URI.
385  */
START_TEST(test_ns_extend_uri_buffer)386 START_TEST(test_ns_extend_uri_buffer) {
387   const char *text = "<foo:e xmlns:foo='http://example.org/'>"
388                      " <foo:thisisalongenoughnametotriggerallocationaction"
389                      "   foo:a='12' />"
390                      "</foo:e>";
391   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
392       == XML_STATUS_ERROR)
393     xml_failure(g_parser);
394 }
395 END_TEST
396 
397 /* Test that xmlns is correctly rejected as an attribute in the xmlns
398  * namespace, but not in other namespaces
399  */
START_TEST(test_ns_reserved_attributes)400 START_TEST(test_ns_reserved_attributes) {
401   const char *text1
402       = "<foo:e xmlns:foo='http://example.org/' xmlns:xmlns='12' />";
403   const char *text2
404       = "<foo:e xmlns:foo='http://example.org/' foo:xmlns='12' />";
405   expect_failure(text1, XML_ERROR_RESERVED_PREFIX_XMLNS,
406                  "xmlns not rejected as an attribute");
407   XML_ParserReset(g_parser, NULL);
408   if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
409       == XML_STATUS_ERROR)
410     xml_failure(g_parser);
411 }
412 END_TEST
413 
414 /* Test more reserved attributes */
START_TEST(test_ns_reserved_attributes_2)415 START_TEST(test_ns_reserved_attributes_2) {
416   const char *text1 = "<foo:e xmlns:foo='http://example.org/'"
417                       "  xmlns:xml='http://example.org/' />";
418   const char *text2
419       = "<foo:e xmlns:foo='http://www.w3.org/XML/1998/namespace' />";
420   const char *text3 = "<foo:e xmlns:foo='http://www.w3.org/2000/xmlns/' />";
421 
422   expect_failure(text1, XML_ERROR_RESERVED_PREFIX_XML,
423                  "xml not rejected as an attribute");
424   XML_ParserReset(g_parser, NULL);
425   expect_failure(text2, XML_ERROR_RESERVED_NAMESPACE_URI,
426                  "Use of w3.org URL not faulted");
427   XML_ParserReset(g_parser, NULL);
428   expect_failure(text3, XML_ERROR_RESERVED_NAMESPACE_URI,
429                  "Use of w3.org xmlns URL not faulted");
430 }
431 END_TEST
432 
433 /* Test string pool handling of namespace names of 2048 characters */
434 /* Exercises a particular string pool growth path */
START_TEST(test_ns_extremely_long_prefix)435 START_TEST(test_ns_extremely_long_prefix) {
436   /* C99 compilers are only required to support 4095-character
437    * strings, so the following needs to be split in two to be safe
438    * for all compilers.
439    */
440   const char *text1
441       = "<doc "
442         /* 64 character on each line */
443         /* ...gives a total length of 2048 */
444         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
445         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
446         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
447         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
448         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
449         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
450         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
451         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
452         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
453         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
454         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
455         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
456         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
457         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
458         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
459         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
460         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
461         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
462         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
463         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
464         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
465         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
466         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
467         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
468         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
469         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
470         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
471         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
472         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
473         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
474         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
475         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
476         ":a='12'";
477   const char *text2
478       = " xmlns:"
479         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
480         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
481         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
482         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
483         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
484         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
485         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
486         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
487         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
488         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
489         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
490         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
491         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
492         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
493         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
494         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
495         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
496         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
497         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
498         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
499         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
500         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
501         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
502         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
503         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
504         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
505         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
506         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
507         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
508         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
509         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
510         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
511         "='foo'\n>"
512         "</doc>";
513 
514   if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
515       == XML_STATUS_ERROR)
516     xml_failure(g_parser);
517   if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
518       == XML_STATUS_ERROR)
519     xml_failure(g_parser);
520 }
521 END_TEST
522 
523 /* Test unknown encoding handlers in namespace setup */
START_TEST(test_ns_unknown_encoding_success)524 START_TEST(test_ns_unknown_encoding_success) {
525   const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
526                      "<foo:e xmlns:foo='http://example.org/'>Hi</foo:e>";
527 
528   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
529   run_character_check(text, XCS("Hi"));
530 }
531 END_TEST
532 
533 /* Test that too many colons are rejected */
START_TEST(test_ns_double_colon)534 START_TEST(test_ns_double_colon) {
535   const char *text = "<foo:e xmlns:foo='http://example.org/' foo:a:b='bar' />";
536   const enum XML_Status status
537       = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
538 #ifdef XML_NS
539   if ((status == XML_STATUS_OK)
540       || (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)) {
541     fail("Double colon in attribute name not faulted"
542          " (despite active namespace support)");
543   }
544 #else
545   if (status != XML_STATUS_OK) {
546     fail("Double colon in attribute name faulted"
547          " (despite inactive namespace support");
548   }
549 #endif
550 }
551 END_TEST
552 
START_TEST(test_ns_double_colon_element)553 START_TEST(test_ns_double_colon_element) {
554   const char *text = "<foo:bar:e xmlns:foo='http://example.org/' />";
555   const enum XML_Status status
556       = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
557 #ifdef XML_NS
558   if ((status == XML_STATUS_OK)
559       || (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)) {
560     fail("Double colon in element name not faulted"
561          " (despite active namespace support)");
562   }
563 #else
564   if (status != XML_STATUS_OK) {
565     fail("Double colon in element name faulted"
566          " (despite inactive namespace support");
567   }
568 #endif
569 }
570 END_TEST
571 
572 /* Test that non-name characters after a colon are rejected */
START_TEST(test_ns_bad_attr_leafname)573 START_TEST(test_ns_bad_attr_leafname) {
574   const char *text = "<foo:e xmlns:foo='http://example.org/' foo:?ar='baz' />";
575 
576   expect_failure(text, XML_ERROR_INVALID_TOKEN,
577                  "Invalid character in leafname not faulted");
578 }
579 END_TEST
580 
START_TEST(test_ns_bad_element_leafname)581 START_TEST(test_ns_bad_element_leafname) {
582   const char *text = "<foo:?oc xmlns:foo='http://example.org/' />";
583 
584   expect_failure(text, XML_ERROR_INVALID_TOKEN,
585                  "Invalid character in element leafname not faulted");
586 }
587 END_TEST
588 
589 /* Test high-byte-set UTF-16 characters are valid in a leafname */
START_TEST(test_ns_utf16_leafname)590 START_TEST(test_ns_utf16_leafname) {
591   const char text[] =
592       /* <n:e xmlns:n='URI' n:{KHO KHWAI}='a' />
593        * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
594        */
595       "<\0n\0:\0e\0 \0x\0m\0l\0n\0s\0:\0n\0=\0'\0U\0R\0I\0'\0 \0"
596       "n\0:\0\x04\x0e=\0'\0a\0'\0 \0/\0>\0";
597   const XML_Char *expected = XCS("a");
598   CharData storage;
599 
600   CharData_Init(&storage);
601   XML_SetStartElementHandler(g_parser, accumulate_attribute);
602   XML_SetUserData(g_parser, &storage);
603   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
604       == XML_STATUS_ERROR)
605     xml_failure(g_parser);
606   CharData_CheckXMLChars(&storage, expected);
607 }
608 END_TEST
609 
START_TEST(test_ns_utf16_element_leafname)610 START_TEST(test_ns_utf16_element_leafname) {
611   const char text[] =
612       /* <n:{KHO KHWAI} xmlns:n='URI'/>
613        * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
614        */
615       "\0<\0n\0:\x0e\x04\0 \0x\0m\0l\0n\0s\0:\0n\0=\0'\0U\0R\0I\0'\0/\0>";
616 #ifdef XML_UNICODE
617   const XML_Char *expected = XCS("URI \x0e04");
618 #else
619   const XML_Char *expected = XCS("URI \xe0\xb8\x84");
620 #endif
621   CharData storage;
622 
623   CharData_Init(&storage);
624   XML_SetStartElementHandler(g_parser, start_element_event_handler);
625   XML_SetUserData(g_parser, &storage);
626   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
627       == XML_STATUS_ERROR)
628     xml_failure(g_parser);
629   CharData_CheckXMLChars(&storage, expected);
630 }
631 END_TEST
632 
START_TEST(test_ns_utf16_doctype)633 START_TEST(test_ns_utf16_doctype) {
634   const char text[] =
635       /* <!DOCTYPE foo:{KHO KHWAI} [ <!ENTITY bar 'baz'> ]>\n
636        * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
637        */
638       "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0f\0o\0o\0:\x0e\x04\0 "
639       "\0[\0 \0<\0!\0E\0N\0T\0I\0T\0Y\0 \0b\0a\0r\0 \0'\0b\0a\0z\0'\0>\0 "
640       "\0]\0>\0\n"
641       /* <foo:{KHO KHWAI} xmlns:foo='URI'>&bar;</foo:{KHO KHWAI}> */
642       "\0<\0f\0o\0o\0:\x0e\x04\0 "
643       "\0x\0m\0l\0n\0s\0:\0f\0o\0o\0=\0'\0U\0R\0I\0'\0>"
644       "\0&\0b\0a\0r\0;"
645       "\0<\0/\0f\0o\0o\0:\x0e\x04\0>";
646 #ifdef XML_UNICODE
647   const XML_Char *expected = XCS("URI \x0e04");
648 #else
649   const XML_Char *expected = XCS("URI \xe0\xb8\x84");
650 #endif
651   CharData storage;
652 
653   CharData_Init(&storage);
654   XML_SetUserData(g_parser, &storage);
655   XML_SetStartElementHandler(g_parser, start_element_event_handler);
656   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
657   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
658       == XML_STATUS_ERROR)
659     xml_failure(g_parser);
660   CharData_CheckXMLChars(&storage, expected);
661 }
662 END_TEST
663 
START_TEST(test_ns_invalid_doctype)664 START_TEST(test_ns_invalid_doctype) {
665   const char *text = "<!DOCTYPE foo:!bad [ <!ENTITY bar 'baz' ]>\n"
666                      "<foo:!bad>&bar;</foo:!bad>";
667 
668   expect_failure(text, XML_ERROR_INVALID_TOKEN,
669                  "Invalid character in document local name not faulted");
670 }
671 END_TEST
672 
START_TEST(test_ns_double_colon_doctype)673 START_TEST(test_ns_double_colon_doctype) {
674   const char *text = "<!DOCTYPE foo:a:doc [ <!ENTITY bar 'baz' ]>\n"
675                      "<foo:a:doc>&bar;</foo:a:doc>";
676 
677   expect_failure(text, XML_ERROR_SYNTAX,
678                  "Double colon in document name not faulted");
679 }
680 END_TEST
681 
START_TEST(test_ns_separator_in_uri)682 START_TEST(test_ns_separator_in_uri) {
683   struct test_case {
684     enum XML_Status expectedStatus;
685     const char *doc;
686     XML_Char namesep;
687   };
688   struct test_case cases[] = {
689       {XML_STATUS_OK, "<doc xmlns='one_two' />", XCS('\n')},
690       {XML_STATUS_ERROR, "<doc xmlns='one&#x0A;two' />", XCS('\n')},
691       {XML_STATUS_OK, "<doc xmlns='one:two' />", XCS(':')},
692   };
693 
694   size_t i = 0;
695   size_t failCount = 0;
696   for (; i < sizeof(cases) / sizeof(cases[0]); i++) {
697     set_subtest("%s", cases[i].doc);
698     XML_Parser parser = XML_ParserCreateNS(NULL, cases[i].namesep);
699     XML_SetElementHandler(parser, dummy_start_element, dummy_end_element);
700     if (_XML_Parse_SINGLE_BYTES(parser, cases[i].doc, (int)strlen(cases[i].doc),
701                                 /*isFinal*/ XML_TRUE)
702         != cases[i].expectedStatus) {
703       failCount++;
704     }
705     XML_ParserFree(parser);
706   }
707 
708   if (failCount) {
709     fail("Namespace separator handling is broken");
710   }
711 }
712 END_TEST
713 
714 void
make_namespace_test_case(Suite * s)715 make_namespace_test_case(Suite *s) {
716   TCase *tc_namespace = tcase_create("XML namespaces");
717 
718   suite_add_tcase(s, tc_namespace);
719   tcase_add_checked_fixture(tc_namespace, namespace_setup, namespace_teardown);
720   tcase_add_test(tc_namespace, test_return_ns_triplet);
721   tcase_add_test(tc_namespace, test_ns_parser_reset);
722   tcase_add_test(tc_namespace, test_ns_tagname_overwrite);
723   tcase_add_test(tc_namespace, test_ns_tagname_overwrite_triplet);
724   tcase_add_test(tc_namespace, test_start_ns_clears_start_element);
725   tcase_add_test__ifdef_xml_dtd(tc_namespace,
726                                 test_default_ns_from_ext_subset_and_ext_ge);
727   tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_1);
728   tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_2);
729   tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_3);
730   tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_4);
731   tcase_add_test(tc_namespace, test_ns_unbound_prefix);
732   tcase_add_test(tc_namespace, test_ns_default_with_empty_uri);
733   tcase_add_test(tc_namespace, test_ns_duplicate_attrs_diff_prefixes);
734   tcase_add_test(tc_namespace, test_ns_duplicate_hashes);
735   tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_attribute);
736   tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_element);
737   tcase_add_test(tc_namespace, test_ns_long_element);
738   tcase_add_test(tc_namespace, test_ns_mixed_prefix_atts);
739   tcase_add_test(tc_namespace, test_ns_extend_uri_buffer);
740   tcase_add_test(tc_namespace, test_ns_reserved_attributes);
741   tcase_add_test(tc_namespace, test_ns_reserved_attributes_2);
742   tcase_add_test(tc_namespace, test_ns_extremely_long_prefix);
743   tcase_add_test(tc_namespace, test_ns_unknown_encoding_success);
744   tcase_add_test(tc_namespace, test_ns_double_colon);
745   tcase_add_test(tc_namespace, test_ns_double_colon_element);
746   tcase_add_test(tc_namespace, test_ns_bad_attr_leafname);
747   tcase_add_test(tc_namespace, test_ns_bad_element_leafname);
748   tcase_add_test(tc_namespace, test_ns_utf16_leafname);
749   tcase_add_test(tc_namespace, test_ns_utf16_element_leafname);
750   tcase_add_test__if_xml_ge(tc_namespace, test_ns_utf16_doctype);
751   tcase_add_test(tc_namespace, test_ns_invalid_doctype);
752   tcase_add_test(tc_namespace, test_ns_double_colon_doctype);
753   tcase_add_test(tc_namespace, test_ns_separator_in_uri);
754 }
755