diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/AbstractSwaggerUiConfigProperties.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/AbstractSwaggerUiConfigProperties.java
index b39a6c0cb..66c0ff7d0 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/AbstractSwaggerUiConfigProperties.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/AbstractSwaggerUiConfigProperties.java
@@ -185,6 +185,29 @@ public abstract class AbstractSwaggerUiConfigProperties {
*/
protected Boolean withCredentials;
+ /**
+ * The Document title.
+ */
+ protected String documentTitle;
+
+ /**
+ * Gets document title.
+ *
+ * @return the document title
+ */
+ public String getDocumentTitle() {
+ return documentTitle;
+ }
+
+ /**
+ * Sets document title.
+ *
+ * @param documentTitle the document title
+ */
+ public void setDocumentTitle(String documentTitle) {
+ this.documentTitle = documentTitle;
+ }
+
/**
* Gets with credentials.
*
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/ui/AbstractSwaggerIndexTransformer.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/ui/AbstractSwaggerIndexTransformer.java
index 1f48e038e..845d8d207 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/ui/AbstractSwaggerIndexTransformer.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/ui/AbstractSwaggerIndexTransformer.java
@@ -59,6 +59,11 @@ public class AbstractSwaggerIndexTransformer {
*/
private static final String PRESETS = "presets: [";
+ /**
+ * The constant EDITOR_FOLD_MARKER.
+ */
+ private static final String EDITOR_FOLD_MARKER = "//";
+
/**
* The Swagger ui o auth properties.
*/
@@ -178,6 +183,9 @@ else if (swaggerUiConfig.getCsrf().isUseSessionStorage())
html = setConfiguredApiDocsUrl(html);
}
+ if (StringUtils.isNotEmpty(swaggerUiConfig.getDocumentTitle()))
+ html = addDocumentTitle(html);
+
return html;
}
@@ -325,4 +333,41 @@ protected String addSyntaxHighlight(String html) {
return html.replace(PRESETS, stringBuilder.toString());
}
+ /**
+ * Add document title script.
+ *
+ * @param html the html
+ * @return the string
+ */
+ protected String addDocumentTitle(String html) {
+ if (!html.contains(EDITOR_FOLD_MARKER)) {
+ return html;
+ }
+ StringBuilder stringBuilder = new StringBuilder("document.title = '");
+ stringBuilder.append(escapeJavaScriptString(swaggerUiConfig.getDocumentTitle()));
+ stringBuilder.append("';\n\n ");
+ stringBuilder.append(EDITOR_FOLD_MARKER);
+ return html.replace(EDITOR_FOLD_MARKER, stringBuilder.toString());
+ }
+
+ /**
+ * Escape special characters for JavaScript string literal.
+ *
+ * @param input the input string
+ * @return the escaped string
+ */
+ private String escapeJavaScriptString(String input) {
+ if (input == null) {
+ return "";
+ }
+ return input
+ .replace("\\", "\\\\")
+ .replace("'", "\\'")
+ .replace("\n", "\\n")
+ .replace("\r", "\\r")
+ .replace("\t", "\\t")
+ .replace("<", "\\u003c")
+ .replace(">", "\\u003e");
+ }
+
}
diff --git a/springdoc-openapi-starter-common/src/test/java/org/springdoc/ui/AbstractSwaggerIndexTransformerTest.java b/springdoc-openapi-starter-common/src/test/java/org/springdoc/ui/AbstractSwaggerIndexTransformerTest.java
index c103a063b..b5cb304e2 100644
--- a/springdoc-openapi-starter-common/src/test/java/org/springdoc/ui/AbstractSwaggerIndexTransformerTest.java
+++ b/springdoc-openapi-starter-common/src/test/java/org/springdoc/ui/AbstractSwaggerIndexTransformerTest.java
@@ -18,6 +18,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.not;
@ExtendWith(MockitoExtension.class)
class AbstractSwaggerIndexTransformerTest {
@@ -67,4 +68,63 @@ void setApiDocUrlCorrectly() throws IOException {
var html = underTest.defaultTransformations(new SwaggerUiConfigParameters(swaggerUiConfig), is);
assertThat(html, containsString(apiDocUrl));
}
+
+ @Test
+ void documentTitle_whenSet_addsDocumentTitleScript() throws IOException {
+ swaggerUiConfig.setDocumentTitle("My Custom API Documentation");
+ InputStream inputStream = new ByteArrayInputStream(swaggerInitJs.getBytes(StandardCharsets.UTF_8));
+ var html = underTest.defaultTransformations(new SwaggerUiConfigParameters(swaggerUiConfig), inputStream);
+ assertThat(html, containsString("document.title = 'My Custom API Documentation';"));
+ }
+
+ @Test
+ void documentTitle_whenNotSet_doesNotAddScript() throws IOException {
+ swaggerUiConfig.setDocumentTitle(null);
+ InputStream inputStream = new ByteArrayInputStream(swaggerInitJs.getBytes(StandardCharsets.UTF_8));
+ var html = underTest.defaultTransformations(new SwaggerUiConfigParameters(swaggerUiConfig), inputStream);
+ assertThat(html, not(containsString("document.title")));
+ }
+
+ @Test
+ void documentTitle_whenEmpty_doesNotAddScript() throws IOException {
+ swaggerUiConfig.setDocumentTitle("");
+ InputStream inputStream = new ByteArrayInputStream(swaggerInitJs.getBytes(StandardCharsets.UTF_8));
+ var html = underTest.defaultTransformations(new SwaggerUiConfigParameters(swaggerUiConfig), inputStream);
+ assertThat(html, not(containsString("document.title")));
+ }
+
+ @Test
+ void documentTitle_escapesSpecialCharacters() throws IOException {
+ swaggerUiConfig.setDocumentTitle("Test's API \\ Documentation");
+ InputStream inputStream = new ByteArrayInputStream(swaggerInitJs.getBytes(StandardCharsets.UTF_8));
+ var html = underTest.defaultTransformations(new SwaggerUiConfigParameters(swaggerUiConfig), inputStream);
+ assertThat(html, containsString("document.title = 'Test\\'s API \\\\ Documentation';"));
+ }
+
+ @Test
+ void documentTitle_escapesNewlines() throws IOException {
+ swaggerUiConfig.setDocumentTitle("Test\nAPI\rDocs\tTitle");
+ InputStream inputStream = new ByteArrayInputStream(swaggerInitJs.getBytes(StandardCharsets.UTF_8));
+ var html = underTest.defaultTransformations(new SwaggerUiConfigParameters(swaggerUiConfig), inputStream);
+ assertThat(html, containsString("document.title = 'Test\\nAPI\\rDocs\\tTitle';"));
+ }
+
+ @Test
+ void documentTitle_escapesScriptTags() throws IOException {
+ swaggerUiConfig.setDocumentTitle("");
+ InputStream inputStream = new ByteArrayInputStream(swaggerInitJs.getBytes(StandardCharsets.UTF_8));
+ var html = underTest.defaultTransformations(new SwaggerUiConfigParameters(swaggerUiConfig), inputStream);
+ assertThat(html, not(containsString("