Skip to content

Commit 3272e25

Browse files
committed
8305710: Line breaks in search tags cause invalid JSON in index file
Reviewed-by: jjg
1 parent 3f4abff commit 3272e25

File tree

4 files changed

+68
-29
lines changed

4 files changed

+68
-29
lines changed

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ $.widget("custom.catcomplete", $.ui.autocomplete, {
366366
? item.l
367367
: getHighlightedText(item.input, item.boundaries, 0, item.input.length);
368368
var idx = item.indexItem;
369-
if (item.category === "searchTags" && idx.h) {
369+
if (item.category === "searchTags" && idx && idx.h) {
370370
if (idx.d) {
371371
div.html(label + "<span class='search-tag-holder-result'> (" + idx.h + ")</span><br><span class='search-tag-desc-result'>"
372372
+ idx.d + "</span><br>");

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexItem.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,9 @@ private IndexItem(Element element, String label) {
269269
if (label.isEmpty()) {
270270
throw new IllegalArgumentException();
271271
}
272+
if (label.contains("\n") || label.contains("\r")) {
273+
throw new IllegalArgumentException();
274+
}
272275

273276
this.element = element;
274277
this.label = label;
@@ -578,6 +581,6 @@ public String toJSON() {
578581
}
579582

580583
private String escapeQuotes(String s) {
581-
return s.replace("\"", "\\\"");
584+
return s.replace("\\", "\\\\").replace("\"", "\\\"");
582585
}
583586
}

test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,7 @@
2626
* @bug 8141492 8071982 8141636 8147890 8166175 8168965 8176794 8175218 8147881
2727
* 8181622 8182263 8074407 8187521 8198522 8182765 8199278 8196201 8196202
2828
* 8184205 8214468 8222548 8223378 8234746 8241219 8254627 8247994 8263528
29-
* 8266808 8248863
29+
* 8266808 8248863 8305710
3030
* @summary Test the search feature of javadoc.
3131
* @library ../../lib
3232
* @modules jdk.javadoc/jdk.javadoc.internal.tool
@@ -56,7 +56,7 @@ public void test1() {
5656
"-use",
5757
testSrc("UnnamedPkgClass.java"));
5858
checkExit(Exit.OK);
59-
checkSearchOutput("UnnamedPkgClass.html", true, true);
59+
checkSearchOutput("UnnamedPkgClass.html", true);
6060
checkJqueryAndImageFiles(true);
6161
checkSearchJS();
6262
checkFiles(true,
@@ -78,8 +78,9 @@ public void test2() {
7878
checkExit(Exit.OK);
7979
checkInvalidUsageIndexTag();
8080
checkSearchOutput(true);
81-
checkSingleIndex(true, true);
81+
checkSingleIndex();
8282
checkSingleIndexSearchTagDuplication();
83+
checkSearchTagIndex();
8384
checkJqueryAndImageFiles(true);
8485
checkSearchJS();
8586
checkAllPkgsAllClasses();
@@ -102,8 +103,9 @@ public void test2a() {
102103
checkExit(Exit.ERROR);
103104
checkDocLintErrors();
104105
checkSearchOutput(true);
105-
checkSingleIndex(true, true);
106+
checkSingleIndex();
106107
checkSingleIndexSearchTagDuplication();
108+
checkSearchTagIndex();
107109
checkJqueryAndImageFiles(true);
108110
checkSearchJS();
109111
checkFiles(true,
@@ -147,7 +149,7 @@ public void test4() {
147149
"pkg", "pkg1", "pkg2", "pkg3");
148150
checkExit(Exit.OK);
149151
checkSearchOutput(true);
150-
checkSingleIndex(true, true);
152+
checkSingleIndex();
151153
checkSingleIndexSearchTagDuplication();
152154
checkJqueryAndImageFiles(true);
153155
checkSearchJS();
@@ -279,7 +281,7 @@ public void testURLEncoding() {
279281
"pkg", "pkg1", "pkg2", "pkg3");
280282
checkExit(Exit.OK);
281283
checkSearchJS();
282-
checkSearchIndex(true);
284+
checkSearchIndex();
283285
}
284286

285287
@Test
@@ -299,7 +301,7 @@ public void testDefaultJapaneseLocale() {
299301
"\u30d1\u30c3\u30b1\u30fc\u30b8pkg1\u306e\u30bd\u30fc\u30b9\u30fb\u30d5\u30a1" +
300302
"\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u3093\u3067\u3044\u307e\u3059...\n");
301303
checkSearchJS();
302-
checkSearchIndex(true);
304+
checkSearchIndex();
303305
} finally {
304306
Locale.setDefault(prev);
305307
}
@@ -324,7 +326,7 @@ public void testJapaneseLocaleOption() {
324326
checkOutput("index.html", true,
325327
"<span>\u30d1\u30c3\u30b1\u30fc\u30b8</span>");
326328
checkSearchJS();
327-
checkSearchIndex(true);
329+
checkSearchIndex();
328330
}
329331

330332
@Test
@@ -344,7 +346,7 @@ public void testDefaultChineseLocale() {
344346
"\u6b63\u5728\u52a0\u8f7d\u7a0b\u5e8f\u5305pkg2\u7684\u6e90\u6587\u4ef6...\n",
345347
"\u6b63\u5728\u52a0\u8f7d\u7a0b\u5e8f\u5305pkg3\u7684\u6e90\u6587\u4ef6...\n");
346348
checkSearchJS();
347-
checkSearchIndex(true);
349+
checkSearchIndex();
348350
} finally {
349351
Locale.setDefault(prev);
350352
}
@@ -375,7 +377,7 @@ public void testChineseLocaleOption() {
375377
checkOutput("index.html", true,
376378
"<span>\u7a0b\u5e8f\u5305</span>");
377379
checkSearchJS();
378-
checkSearchIndex(true);
380+
checkSearchIndex();
379381
}
380382

381383
void checkDocLintErrors() {
@@ -387,12 +389,8 @@ void checkDocLintErrors() {
387389
"A test field. Testing only white-spaces in index tag text {@index }.");
388390
}
389391

390-
void checkSearchOutput(boolean expectedOutput) {
391-
checkSearchOutput("index.html", expectedOutput, true);
392-
}
393-
394-
void checkSearchIndex(boolean expectedOutput) {
395-
checkOutput("member-search-index.js", expectedOutput,
392+
void checkSearchIndex() {
393+
checkOutput("member-search-index.js", true,
396394
"""
397395
{"p":"pkg","c":"AnotherClass","l":"AnotherClass()","u":"%3Cinit%3E()"}""",
398396
"""
@@ -401,7 +399,7 @@ void checkSearchIndex(boolean expectedOutput) {
401399
{"p":"pkg2","c":"TestError","l":"TestError()","u":"%3Cinit%3E()"}""",
402400
"""
403401
{"p":"pkg","c":"AnotherClass","l":"method(byte[], int, String)","u":"method(byte[],int,java.lang.String)"}""");
404-
checkOutput("member-search-index.js", !expectedOutput,
402+
checkOutput("member-search-index.js", false,
405403
"""
406404
{"p":"pkg","c":"AnotherClass","l":"method(RegClass)","u":"method-pkg1.RegClass-"}""",
407405
"""
@@ -412,11 +410,11 @@ void checkSearchIndex(boolean expectedOutput) {
412410
{"p":"pkg","c":"AnotherClass","l":"method(byte[], int, String)","u":"method-byte:A-int-java.lang.String-"}""");
413411
}
414412

415-
void checkSearchOutput(boolean expectedOutput, boolean moduleDirectoriesVar) {
416-
checkSearchOutput("index.html", expectedOutput, moduleDirectoriesVar);
413+
void checkSearchOutput(boolean expectedOutput) {
414+
checkSearchOutput("index.html", expectedOutput);
417415
}
418416

419-
void checkSearchOutput(String fileName, boolean expectedOutput, boolean moduleDirectoriesVar) {
417+
void checkSearchOutput(String fileName, boolean expectedOutput) {
420418
// Test for search related markup
421419
checkOutput(fileName, expectedOutput,
422420
"""
@@ -440,11 +438,9 @@ void checkSearchOutput(String fileName, boolean expectedOutput, boolean moduleDi
440438
"<div class=\"flex-box\">");
441439
}
442440

443-
void checkSingleIndex(boolean expectedOutput, boolean html5) {
444-
String html_span_see_span = html5 ? "html%3Cspan%3Esee%3C/span%3E" : "html-span-see-/span-";
445-
441+
void checkSingleIndex() {
446442
// Test for search tags markup in index file.
447-
checkOutput("index-all.html", expectedOutput,
443+
checkOutput("index-all.html", true,
448444
"""
449445
<dt><a href="pkg/package-summary.html#phrasewithspaces" class="search-tag-link">\
450446
phrase with spaces</a> - Search tag in package pkg</dt>""",
@@ -491,7 +487,7 @@ void checkSingleIndex(boolean expectedOutput, boolean html5) {
491487
test%7D" class="search-tag-link">nested {@index nested_tag_test}</a> - Search ta\
492488
g in pkg.AnotherClass.ModalExclusionType.NO_EXCLUDE</dt>""",
493489
"""
494-
<dt><a href="pkg/AnotherClass.ModalExclusionType.html#""" + html_span_see_span + """
490+
<dt><a href="pkg/AnotherClass.ModalExclusionType.html#html%3Cspan%3Esee%3C/span%3E\
495491
" class="search-tag-link">html &lt;span&gt; see &lt;/span&gt;</a> - Search tag i\
496492
n pkg.AnotherClass.ModalExclusionType.APPLICATION_EXCLUDE</dt>""",
497493
"""
@@ -830,4 +826,44 @@ void checkAllPkgsAllClasses() {
830826
s</a><span class="vertical-separator">|</span><a href="allpackages-index.htm\
831827
l">All&nbsp;Packages</a>""");
832828
}
829+
830+
void checkSearchTagIndex() {
831+
checkOutput("tag-search-index.js", true,
832+
"""
833+
{"l":"html <span> see </span>","h":"pkg.AnotherClass.ModalExclusionType.APPLICATION_EXCLUDE","u":"pkg/AnotherClass.ModalExclusionType.html#html<span>see</span>"}""",
834+
"""
835+
{"l":"nested {@index nested_tag_test}","h":"pkg.AnotherClass.ModalExclusionType.NO_EXCLUDE","u":"pkg/AnotherClass.ModalExclusionType.html#nested{@indexnested_tag_test}"}""",
836+
"""
837+
{"l":"phrase with spaces","h":"package pkg","u":"pkg/package-summary.html#phrasewithspaces"},{"l":"pkg","h":"package pkg","u":"pkg/package-summary.html#pkg"}""",
838+
"""
839+
{"l":"quoted","h":"pkg.AnotherClass.CONSTANT1","d":"no-space","u":"pkg/AnotherClass.html#quoted"}""",
840+
"""
841+
{"l":"r","h":"package pkg","u":"pkg/package-summary.html#r"}""",
842+
"""
843+
{"l":"search phrase","h":"class pkg1.RegClass","d":"with description","u":"pkg1/RegClass.html#searchphrase"}""",
844+
"""
845+
{"l":"search phrase deprecated","h":"pkg2.TestEnum.ONE","u":"deprecated-list.html#searchphrasedeprecated"}""",
846+
"""
847+
{"l":"search phrase deprecated","h":"pkg2.TestEnum.ONE","u":"pkg2/TestEnum.html#searchphrasedeprecated"}""",
848+
"""
849+
{"l":"search phrase with desc deprecated","h":"annotation interface pkg2.TestAnnotationType","d":"description for phrase deprecated","u":"deprecated-list.html#searchphrasewithdescdeprecated"}""",
850+
"""
851+
{"l":"search phrase with desc deprecated","h":"annotation interface pkg2.TestAnnotationType","d":"description for phrase deprecated","u":"pkg2/TestAnnotationType.html#searchphrasewithdescdeprecated"}""",
852+
"""
853+
{"l":"SearchTagDeprecatedClass","h":"class pkg2.TestClass","u":"deprecated-list.html#SearchTagDeprecatedClass"}""",
854+
"""
855+
{"l":"SearchTagDeprecatedClass","h":"class pkg2.TestClass","u":"pkg2/TestClass.html#SearchTagDeprecatedClass"}""",
856+
"""
857+
{"l":"SearchTagDeprecatedMethod","h":"pkg2.TestError.TestError()","d":"with description","u":"deprecated-list.html#SearchTagDeprecatedMethod"}""",
858+
"""
859+
{"l":"SearchTagDeprecatedMethod","h":"pkg2.TestError.TestError()","d":"with description","u":"pkg2/TestError.html#SearchTagDeprecatedMethod"}""",
860+
"""
861+
{"l":"search term with spaces","h":"interface pkg.TestInterface","d":"description ","u":"pkg/TestInterface.html#searchtermwithspaces"}""",
862+
"""
863+
{"l":"SearchWordWithDescription","h":"pkg1.RegClass.CONSTANT_FIELD_1","d":"search word with desc","u":"pkg1/RegClass.html#SearchWordWithDescription"}""",
864+
"""
865+
{"l":"Serialized Form","h":"","u":"serialized-form.html"},{"l":"SingleWord","h":"package pkg","u":"pkg/package-summary.html#SingleWord"}""",
866+
"""
867+
{"l":"trailing","h":"pkg.AnotherClass.method(byte[], int, String)","d":"backslash\\\\","u":"pkg/AnotherClass.html#trailing"}]""");
868+
}
833869
}

test/langtools/jdk/javadoc/doclet/testSearch/pkg/AnotherClass.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public pkg1.RegClass method(pkg1.RegClass param) {
7575
}
7676

7777
/**
78-
* Method to test member search index URL.
78+
* Method to test member search index URL. Testing search tag for {@index trailing backslash\}
7979
*
8080
* @param testArray some test array.
8181
* @param testInt some test int.

0 commit comments

Comments
 (0)