From edc63420b40c6f52cb65c0fcd365d7097dfd8e04 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 22 Oct 2025 20:29:04 -0400 Subject: [PATCH 1/8] JSPWIKI-1205 adjusts the handling for too large file attachments. This change, while it addresses the issue, might cause a new issue whereby updatlong an extremely large file might cause OOM errors since the commons file uploader parses and buffers the whole http request. And the way the upload page works, it is not possible to get the correct redirect url without parsing the request. unformately, i don't think there's a way to add an http header to multipart form post from javascript.. open to other opinions on this --- .../wiki/attachment/AttachmentServlet.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java b/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java index bcbb9bc678..a2dccb6932 100644 --- a/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java +++ b/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java @@ -64,6 +64,7 @@ Licensed to the Apache Software Foundation (ASF) under one import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.apache.commons.fileupload2.core.FileUploadByteCountLimitException; /** @@ -388,7 +389,7 @@ protected String upload( final HttpServletRequest req ) throws RedirectException // Check that we have a file upload request if( !JakartaServletFileUpload.isMultipartContent(req) ) { - throw new RedirectException( "Not a file upload", errorPage ); + throw new RedirectException( "Not a file upload", nextPage ); } try { @@ -403,11 +404,15 @@ protected String upload( final HttpServletRequest req ) throws RedirectException final JakartaServletFileUpload upload = new JakartaServletFileUpload( factory ); upload.setHeaderCharset(StandardCharsets.UTF_8); if( !context.hasAdminPermissions() ) { - upload.setFileSizeMax( m_maxSize ); + //upload.setFileSizeMax( m_maxSize ); } upload.setProgressListener( pl ); - final List items = upload.parseRequest( req ); - + final List items; + try { + items = upload.parseRequest(req); + } catch (FileUploadByteCountLimitException ex) { + throw new RedirectException( "Too big " + ex.getMessage(), nextPage ); + } String wikipage = null; String changeNote = null; //FileItem actualFile = null; @@ -440,10 +445,16 @@ protected String upload( final HttpServletRequest req ) throws RedirectException } if(fileItems.isEmpty()) { - throw new RedirectException( "Broken file upload", errorPage ); + throw new RedirectException( "Broken file upload", nextPage ); } else { for( final FileItem actualFile : fileItems ) { + if( !context.hasAdminPermissions() ) { + if (actualFile.getSize()> m_maxSize) { + throw new RedirectException("Too big " + actualFile.getName() + " " + actualFile.getSize() + " vs " + m_maxSize, nextPage); + } + } + final String filename = actualFile.getName(); final long fileSize = actualFile.getSize(); try( final InputStream in = actualFile.getInputStream() ) { From a1481136461acf355b08942b62538632c66122a5 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 22 Oct 2025 20:32:07 -0400 Subject: [PATCH 2/8] cleanup --- .../java/org/apache/wiki/attachment/AttachmentServlet.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java b/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java index a2dccb6932..b849b7a5c3 100644 --- a/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java +++ b/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java @@ -403,9 +403,6 @@ protected String upload( final HttpServletRequest req ) throws RedirectException final JakartaServletFileUpload upload = new JakartaServletFileUpload( factory ); upload.setHeaderCharset(StandardCharsets.UTF_8); - if( !context.hasAdminPermissions() ) { - //upload.setFileSizeMax( m_maxSize ); - } upload.setProgressListener( pl ); final List items; try { From 0df4e224273d8b15274e5da3de4c8a752ea79e93 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 23 Oct 2025 17:44:48 -0400 Subject: [PATCH 3/8] JS{WIKI-1205 adds a java SPI lookup mechanism and a new rest endpoint that provides a list of server installed plugins and alters the UI to support fetching and displaying them. Alters the Plugin API definition to have two additional methods with default implementations that should hopefully support backwards compat Alters the PluginManager API to include a getDiscoveredPlugins Alters a few of the javascript mechanisms to get the plugin list ti display with the snip suggestions. This seems to cause a duplicate of the IfPlugin Adds a test hello world type plugin to verify this functionality --- .../org/apache/wiki/api/plugin/Plugin.java | 28 +++++ .../wiki/plugin/DefaultPluginManager.java | 20 ++++ .../org/apache/wiki/plugin/PluginManager.java | 10 ++ .../wiki/search/DefaultSearchManager.java | 76 +++++++++++- .../org/apache/wiki/search/SearchManager.java | 3 + .../src/main/javascript/Wiki.Snips.JSPWiki.js | 111 ++++++++++++------ .../main/javascript/Wiki.Snips.Markdown.js | 31 ++++- jspwiki-portable/build.xml | 7 ++ jspwiki-portable/pom.xml | 6 + jspwiki-test-plugin/pom.xml | 21 ++++ .../test/plugin/JspwikiTestPlugin.java | 37 ++++++ .../org.apache.wiki.api.plugin,Plugin | 1 + .../src/main/scripts/jspwiki-common.js | 3 +- .../src/main/scripts/wiki-edit/Snipe.Snips.js | 55 +++++---- jspwiki-war/src/main/scripts/wiki/Wiki.js | 10 +- pom.xml | 1 + 16 files changed, 352 insertions(+), 68 deletions(-) create mode 100644 jspwiki-test-plugin/pom.xml create mode 100644 jspwiki-test-plugin/src/main/java/org/apache/jspwiki/jspwiki/test/plugin/JspwikiTestPlugin.java create mode 100644 jspwiki-test-plugin/src/main/resources/META-INF/services/org.apache.wiki.api.plugin,Plugin diff --git a/jspwiki-api/src/main/java/org/apache/wiki/api/plugin/Plugin.java b/jspwiki-api/src/main/java/org/apache/wiki/api/plugin/Plugin.java index 950496a41a..c37cd30d63 100644 --- a/jspwiki-api/src/main/java/org/apache/wiki/api/plugin/Plugin.java +++ b/jspwiki-api/src/main/java/org/apache/wiki/api/plugin/Plugin.java @@ -48,5 +48,33 @@ public interface Plugin { * @throws PluginException In case anything goes wrong. */ String execute( Context context, Map< String, String > params ) throws PluginException; + + /** + * Provides the ability for a plugin to provide a suggestion or template + * for execution within a wiki page. Default returns just the FQCN of the + * plugin, which should enable it to fire off, however no parameters are + * plugin. + * + * Example: com.company.Plugin inputParamter='test' + * + * @since 3.0.0 + * @return String + */ + default String getSnipExample() { + return this.getClass().getCanonicalName(); + } + /** + * Provides the ability for a plugin to provide it's display name that + * is visible via the [{}] autocomplete/suggestion mechanism within the + * editor. + * + * Example: Calls My Custom plugin + * + * @since 3.0.0 + * @return String + */ + default String getDisplayName() { + return this.getClass().getSimpleName(); + } } diff --git a/jspwiki-main/src/main/java/org/apache/wiki/plugin/DefaultPluginManager.java b/jspwiki-main/src/main/java/org/apache/wiki/plugin/DefaultPluginManager.java index 8e082d4406..49abf6d4e4 100644 --- a/jspwiki-main/src/main/java/org/apache/wiki/plugin/DefaultPluginManager.java +++ b/jspwiki-main/src/main/java/org/apache/wiki/plugin/DefaultPluginManager.java @@ -59,12 +59,16 @@ Licensed to the Apache Software Foundation (ASF) under one import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Properties; import java.util.ResourceBundle; +import java.util.ServiceLoader; +import java.util.Set; import java.util.StringTokenizer; +import java.util.logging.Level; /** * Manages plugin classes. There exists a single instance of PluginManager @@ -715,4 +719,20 @@ public Plugin newWikiPlugin( final String pluginName, final ResourceBundle rb ) return plugin; } + @Override + public List getDiscoveredPlugins() { + Collection pluginModules = modules(); + Set plugins = new HashSet<>(); + for(WikiModuleInfo plugin : pluginModules) { + try { + Plugin p = (Plugin) Class.forName(((WikiPluginInfo)plugin).getClassName()).newInstance(); + plugins.add(p); + } catch (Throwable ex) { + LOG.error("failed to load class " + plugin.getName(), ex); + } + } + + return new ArrayList<>(plugins); + } + } diff --git a/jspwiki-main/src/main/java/org/apache/wiki/plugin/PluginManager.java b/jspwiki-main/src/main/java/org/apache/wiki/plugin/PluginManager.java index aa5f752fb1..552e4c97b9 100644 --- a/jspwiki-main/src/main/java/org/apache/wiki/plugin/PluginManager.java +++ b/jspwiki-main/src/main/java/org/apache/wiki/plugin/PluginManager.java @@ -25,6 +25,7 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.wiki.modules.ModuleManager; import java.io.IOException; +import java.util.List; import java.util.Map; import java.util.ResourceBundle; @@ -129,4 +130,13 @@ public interface PluginManager extends ModuleManager { */ Plugin newWikiPlugin( String pluginName, ResourceBundle rb ) throws PluginException; + /** + * gets a list of plugins available via the java service provider discovery + * mechanism. Helpful for populating autocomplete capabilities. + * + * @since 3.0.0 + * @return list of plugin instances. + */ + List getDiscoveredPlugins(); + } diff --git a/jspwiki-main/src/main/java/org/apache/wiki/search/DefaultSearchManager.java b/jspwiki-main/src/main/java/org/apache/wiki/search/DefaultSearchManager.java index c31ae6fda1..1d6b8076fe 100644 --- a/jspwiki-main/src/main/java/org/apache/wiki/search/DefaultSearchManager.java +++ b/jspwiki-main/src/main/java/org/apache/wiki/search/DefaultSearchManager.java @@ -54,6 +54,9 @@ Licensed to the Apache Software Foundation (ASF) under one import java.util.Map; import java.util.Properties; import java.util.Set; +import org.apache.wiki.api.plugin.Plugin; +import org.apache.wiki.plugin.PluginManager; +import static org.apache.wiki.search.SearchManager.PLUGIN_SEARCH; /** @@ -80,8 +83,79 @@ public DefaultSearchManager( final Engine engine, final Properties properties ) // TODO: Replace with custom annotations. See JSPWIKI-566 WikiAjaxDispatcherServlet.registerServlet( JSON_SEARCH, new JSONSearch() ); + WikiAjaxDispatcherServlet.registerServlet( PLUGIN_SEARCH, new PluginSearch() ); } + /** + * Provides a JSON AJAX API to the JSPWiki Plugin discovery mechanism, + * primarily used for [{}] based auto complete + */ + public class PluginSearch implements WikiAjaxServlet { + + public static final String AJAX_ACTION_PLUGINS = "plugins"; + public static final int DEFAULT_MAX_RESULTS = 20; + public int maxResults = DEFAULT_MAX_RESULTS; + + /** {@inheritDoc} */ + @Override + public String getServletMapping() { + return PLUGIN_SEARCH; + } + public static class SimpleSnipData { + public String displayName; + public String snip; + } + + /** {@inheritDoc} */ + @Override + public void service( final HttpServletRequest req, + final HttpServletResponse resp, + final String actionName, + final List< String > params ) throws IOException { + String result = "[]"; + String itemId = null; + if( actionName != null && StringUtils.isNotBlank( actionName ) ) { + if( !params.isEmpty() ) { + itemId = params.get( 0 ); + LOG.debug( "itemId=" + itemId ); + if( params.size() > 1 ) { + itemId = params.get( 0 ); + final String maxResultsParam = params.get( 1 ); + LOG.debug( "maxResultsParam=" + maxResultsParam ); + if( StringUtils.isNotBlank( maxResultsParam ) && StringUtils.isNumeric( maxResultsParam ) ) { + maxResults = Integer.parseInt( maxResultsParam ); + } + } + } + + if( actionName.equals( AJAX_ACTION_PLUGINS ) ) { + LOG.debug( "Calling getPlugins() START" ); + PluginManager mgr = m_engine.getManager(PluginManager.class); + final List< Plugin > plugins = mgr.getDiscoveredPlugins(); + List< SimpleSnipData > callResults = new ArrayList<>(); + for (Plugin p : plugins) { + if ( itemId != null && StringUtils.isNotBlank(itemId) ) { + if ( !p.getSnipExample().startsWith(itemId) ) { + continue; + } + } else { + SimpleSnipData data = new SimpleSnipData(); + data.snip = p.getSnipExample(); + data.displayName = p.getDisplayName(); + callResults.add(data); + } + if ( callResults.size() > maxResults ) + break; + } + LOG.debug( "Calling getSuggestions() DONE. " + callResults.size() ); + result = AjaxUtil.toJson( callResults ); + } + } + LOG.debug( "result=" + result ); + resp.getWriter().write( result ); + } + } + /** * Provides a JSON AJAX API to the JSPWiki Search Engine. */ @@ -160,7 +234,7 @@ public List< String > getSuggestions( String wikiName, final int maxLength ) { final String cleanWikiName = MarkupParser.cleanLink(wikiName).toLowerCase() + filename; final String oldStyleName = MarkupParser.wikifyLink(wikiName).toLowerCase() + filename; final Set< String > allPages = m_engine.getManager( ReferenceManager.class ).findCreated(); - + int counter = 0; for( final Iterator< String > i = allPages.iterator(); i.hasNext() && counter < maxLength; ) { final String p = i.next(); diff --git a/jspwiki-main/src/main/java/org/apache/wiki/search/SearchManager.java b/jspwiki-main/src/main/java/org/apache/wiki/search/SearchManager.java index a483212b13..cb241c3aa3 100644 --- a/jspwiki-main/src/main/java/org/apache/wiki/search/SearchManager.java +++ b/jspwiki-main/src/main/java/org/apache/wiki/search/SearchManager.java @@ -44,6 +44,9 @@ public interface SearchManager extends PageFilter, InternalModule, WikiEventList /** The name of the JSON object that manages search. */ String JSON_SEARCH = "search"; + + /** the name of the Plugin discovery endpoint */ + String PLUGIN_SEARCH = "plugins"; /** * Returns the SearchProvider used. diff --git a/jspwiki-main/src/main/javascript/Wiki.Snips.JSPWiki.js b/jspwiki-main/src/main/javascript/Wiki.Snips.JSPWiki.js index 0a5dfbcadf..634348ce62 100644 --- a/jspwiki-main/src/main/javascript/Wiki.Snips.JSPWiki.js +++ b/jspwiki-main/src/main/javascript/Wiki.Snips.JSPWiki.js @@ -44,7 +44,7 @@ Function: snippets */ Wiki.Snips = { - + ready: false, // Snipe predefined commands find: { }, undo: { event: "undo" }, @@ -519,41 +519,43 @@ Wiki.Snips = { //lback: "(^|[^\\[])\\[{([^\\[\\]\\n\\r]*)(?:\\|\\])?$", match: "^([^\\[\\]\\n\\r]*)\\}\\]" }, - pluginDlg: [ Dialog.Selection, { - caption: "dialog.plugin".localize(), - body: { - "ALLOW {permission} principal ": "Page Access Rights ", - "SET {name}='value'":"Set a Wiki variable", - "${varname}":"Get a Wiki variable", - "If name='{value}' page='pagename' exists='true' contains='regexp'\n\nbody\n":"IF plugin", - "SET keywords={keyword1, keyword2}":"Set Page Keywords", - "SET alias='{pagename}'":"Set Page Alias", - "SET page-styles='prettify-nonum table-condensed-fit'":"Set Page Styles", - "SET sidebar='off'":"Hide Sidebar", - //"Table":"Advanced Tables", - //"Groups":"View all Wiki Groups", - "":"", - "Counter":"Insert a simple counter", - "PageViewPlugin":"Count Views of this page", - "CurrentTimePlugin format='yyyy mmm-dd'":"Insert Current Time", - "Denounce":"Denounce a link", - "Image src='{image.jpg}'":"Insert an Image ", - "IndexPlugin":"Index of all pages", - - "InsertPage page='{pagename}'":"Insert another Page", - "ListLocksPlugin":"List page locks", - "RecentChangesPlugin":"Displays the recent changed pages", - "ReferringPagesPlugin page='{pagename}' separator=',' include='regexp' exclude='regexp'":"Incoming Links (referring pages)", - "ReferredPagesPlugin page='{pagename}' type='local|external|attachment' depth='1..8' include='regexp' exclude='regexp'":"Outgoing Links (referred pages)", - "Search query='{Janne}' max='10'":"Insert a Search query", - "TableOfContents ":"Table Of Contents ", - "UndefinedPagesPlugin":"List pages that are missing", - "UnusedPagesPlugin":"List pages that have been orphaned", - "WeblogArchivePlugin":"Displays a list of older weblog entries", - "WeblogEntryPlugin":"Makes a new weblog entry", - "WeblogPlugin page='{pagename}' startDate='300604' days='30' maxEntries='30' allowComments='false'":"Builds a weblog" - } - }] + pluginDlg: [ Dialog.Selection, + { + caption: "dialog.plugin".localize(), + body: { + "ALLOW {permission} principal ": "Page Access Rights ", + "SET {name}='value'":"Set a Wiki variable", + "${varname}":"Get a Wiki variable", + "If name='{value}' page='pagename' exists='true' contains='regexp'\n\nbody\n":"IF plugin", + "SET keywords={keyword1, keyword2}":"Set Page Keywords", + "SET alias='{pagename}'":"Set Page Alias", + "SET page-styles='prettify-nonum table-condensed-fit'":"Set Page Styles", + "SET sidebar='off'":"Hide Sidebar", + //"Table":"Advanced Tables", + //"Groups":"View all Wiki Groups", + "":"", + "Counter":"Insert a simple counter", + "PageViewPlugin":"Count Views of this page", + "CurrentTimePlugin format='yyyy mmm-dd'":"Insert Current Time", + "Denounce":"Denounce a link", + "Image src='{image.jpg}'":"Insert an Image ", + "IndexPlugin":"Index of all pages", + + "InsertPage page='{pagename}'":"Insert another Page", + "ListLocksPlugin":"List page locks", + "RecentChangesPlugin":"Displays the recent changed pages", + "ReferringPagesPlugin page='{pagename}' separator=',' include='regexp' exclude='regexp'":"Incoming Links (referring pages)", + "ReferredPagesPlugin page='{pagename}' type='local|external|attachment' depth='1..8' include='regexp' exclude='regexp'":"Outgoing Links (referred pages)", + "Search query='{Janne}' max='10'":"Insert a Search query", + "TableOfContents ":"Table Of Contents ", + "UndefinedPagesPlugin":"List pages that are missing", + "UnusedPagesPlugin":"List pages that have been orphaned", + "WeblogArchivePlugin":"Displays a list of older weblog entries", + "WeblogEntryPlugin":"Makes a new weblog entry", + "WeblogPlugin page='{pagename}' startDate='300604' days='30' maxEntries='30' allowComments='false'":"Builds a weblog" + } + } + ] }, @@ -628,5 +630,40 @@ Wiki.Snips = { } }] + }, + +//load up any server defined plugins +//note this file is ran through wro4j maven plugin which is limited ES6 support +//thus the usage of super old xhr requests and var vs let. +//see https://github.com/wro4j/wro4j/issues/1178 + + loadPlugins: function(){ + console.info("loading plugin list"); + const pluginDiscoveryRequest2 = new XMLHttpRequest(); + pluginDiscoveryRequest2.open('GET', 'ajax/plugins/plugins', true); // true for asynchronous + pluginDiscoveryRequest2.onload = function() { + if (pluginDiscoveryRequest2.status >= 200 && pluginDiscoveryRequest2.status < 300) { + var data = JSON.parse(pluginDiscoveryRequest2.responseText); + //Wiki.Snips.pluginDlg["TableOfContents "] = "Table Of Contents "; + for (var i=0; i < data.length; i++) { + Wiki.Snips.pluginDlg.pluginDlg[1].body[data[i].snip] = data[i].displayName; + } + Wiki.Snips.ready = true; + console.info("plugin list loaded"); + } else { + console.error('Request failed. Returned status of ' + pluginDiscoveryRequest2.status); + Wiki.Snips.ready = true; + } + }; + pluginDiscoveryRequest2.onerror = function() { + console.error('Network error occurred'); + Wiki.Snips.ready = true; + }; + pluginDiscoveryRequest2.send(); } -} + + +}; +window.addEventListener("load", function() { + Wiki.Snips.loadPlugins(); +}); \ No newline at end of file diff --git a/jspwiki-markdown/src/main/javascript/Wiki.Snips.Markdown.js b/jspwiki-markdown/src/main/javascript/Wiki.Snips.Markdown.js index 32bc5ce11a..94ccd7a0bd 100644 --- a/jspwiki-markdown/src/main/javascript/Wiki.Snips.Markdown.js +++ b/jspwiki-markdown/src/main/javascript/Wiki.Snips.Markdown.js @@ -44,7 +44,7 @@ Function: snippets */ Wiki.Snips = { - + ready: false, // Snipe predefined commands find: { }, undo: { event: "undo" }, @@ -628,5 +628,32 @@ Wiki.Snips = { } }] + }, + + loadPlugins: function(){ + const pluginDiscoveryRequest2 = new XMLHttpRequest(); + pluginDiscoveryRequest2.open('GET', 'ajax/plugins/plugins', true); // true for asynchronous + pluginDiscoveryRequest2.onload = function() { + if (pluginDiscoveryRequest2.status >= 200 && pluginDiscoveryRequest2.status < 300) { + var data = JSON.parse(pluginDiscoveryRequest2.responseText); + //Wiki.Snips.pluginDlg["TableOfContents "] = "Table Of Contents "; + for (var i=0; i < data.length; i++) { + Wiki.Snips.pluginDlg.pluginDlg[1].body[data[i].snip] = data[i].displayName; + } + Wiki.Snips.ready = true; + } else { + console.error('Request failed. Returned status of ' + pluginDiscoveryRequest2.status); + Wiki.Snips.ready = true; + } + }; + pluginDiscoveryRequest2.onerror = function() { + console.error('Network error occurred'); + Wiki.Snips.ready = true; + }; + pluginDiscoveryRequest2.send(); } -} +}; + +window.addEventListener("load", function() { + Wiki.Snips.loadPlugins(); +}); \ No newline at end of file diff --git a/jspwiki-portable/build.xml b/jspwiki-portable/build.xml index 1c8fb31215..cd140f7fe8 100644 --- a/jspwiki-portable/build.xml +++ b/jspwiki-portable/build.xml @@ -69,12 +69,19 @@ + + + + + + + diff --git a/jspwiki-portable/pom.xml b/jspwiki-portable/pom.xml index b675204d54..43367750ff 100644 --- a/jspwiki-portable/pom.xml +++ b/jspwiki-portable/pom.xml @@ -257,6 +257,12 @@ war provided + + ${project.groupId} + jspwiki-test-plugin + ${project.version} + provided + org.apache.tomcat.embed diff --git a/jspwiki-test-plugin/pom.xml b/jspwiki-test-plugin/pom.xml new file mode 100644 index 0000000000..d7f8f4c8fb --- /dev/null +++ b/jspwiki-test-plugin/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + org.apache.jspwiki + jspwiki-builder + 3.0.0-SNAPSHOT + + jspwiki-test-plugin + jar + + + ${project.groupId} + jspwiki-main + ${project.version} + + + + org.apache.jspwiki.jspwiki.test.plugin.JspwikiTestPlugin + + \ No newline at end of file diff --git a/jspwiki-test-plugin/src/main/java/org/apache/jspwiki/jspwiki/test/plugin/JspwikiTestPlugin.java b/jspwiki-test-plugin/src/main/java/org/apache/jspwiki/jspwiki/test/plugin/JspwikiTestPlugin.java new file mode 100644 index 0000000000..112555ed17 --- /dev/null +++ b/jspwiki-test-plugin/src/main/java/org/apache/jspwiki/jspwiki/test/plugin/JspwikiTestPlugin.java @@ -0,0 +1,37 @@ +/* + * Copyright 2025 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jspwiki.jspwiki.test.plugin; + +import java.util.Map; +import org.apache.wiki.api.core.Context; +import org.apache.wiki.api.exceptions.PluginException; +import org.apache.wiki.api.plugin.Plugin; + +/** + * a simple hello world test plugin + * + * @author AO + */ +public class JspwikiTestPlugin implements Plugin { + + public JspwikiTestPlugin() { + } + + @Override + public String execute(Context context, Map params) throws PluginException { + return "

HelloWorld

"; + } +} diff --git a/jspwiki-test-plugin/src/main/resources/META-INF/services/org.apache.wiki.api.plugin,Plugin b/jspwiki-test-plugin/src/main/resources/META-INF/services/org.apache.wiki.api.plugin,Plugin new file mode 100644 index 0000000000..80a7487ea4 --- /dev/null +++ b/jspwiki-test-plugin/src/main/resources/META-INF/services/org.apache.wiki.api.plugin,Plugin @@ -0,0 +1 @@ +org.apache.jspwiki.jspwiki.test.plugin.JspwikiTestPlugin diff --git a/jspwiki-war/src/main/scripts/jspwiki-common.js b/jspwiki-war/src/main/scripts/jspwiki-common.js index aef3516cd3..4e3fa8cd2e 100644 --- a/jspwiki-war/src/main/scripts/jspwiki-common.js +++ b/jspwiki-war/src/main/scripts/jspwiki-common.js @@ -52,6 +52,7 @@ Complementary Dynamic Styles (see jspwiki-commonstyles.js) * 270 WikiColumns: dynamic style * 300 Prettify: dynamic style +Note this file gets minimied/compiled into haddock.js */ /* extend mootools */ @@ -69,7 +70,7 @@ String.extend({ }); return text; } -}) +}); // get text of a dhtml node function $getText(el) { diff --git a/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Snips.js b/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Snips.js index fcf8e01ce9..0d92391ec4 100644 --- a/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Snips.js +++ b/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Snips.js @@ -55,46 +55,49 @@ Snipe.Snips = new Class({ self.suggestions = {}; for( cmd in snips ){ + try{ + snip = $.toFunction( snips[cmd] )( workarea, cmd ); - snip = $.toFunction( snips[cmd] )( workarea, cmd ); + // short format of snip + if( typeOf(snip) == "string" ){ snip = { snippet:snip }; } - // short format of snip - if( typeOf(snip) == "string" ){ snip = { snippet:snip }; } + //shortcut keys + if(snip.key && (key = snip.key) ){ - //shortcut keys - if( (key = snip.key) ){ + // key: "f" => "control+f" ; key: "shift+enter" (no change) + if( !key.contains( "+" ) ){ key = control + key; } + self.keys[ key.toLowerCase() ] = cmd; - // key: "f" => "control+f" ; key: "shift+enter" (no change) - if( !key.contains( "+" ) ){ key = control + key; } - self.keys[ key.toLowerCase() ] = cmd; + } - } + if( snip.suggest && (suggest = snip.suggest) ){ - if( (suggest = snip.suggest) ){ + //this is a suggest snippets + if( typeOf(suggest) == "string" ){ - //this is a suggest snippets - if( typeOf(suggest) == "string" ){ + snip.suggest = { + lback: RegExp( suggest + "$" ), + match: RegExp( "^" + suggest ) + } - snip.suggest = { - lback: RegExp( suggest + "$" ), - match: RegExp( "^" + suggest ) } - } - - self.suggestions[cmd] = snip; + self.suggestions[cmd] = snip; - //otherwise regular snippet - //} else { + //otherwise regular snippet + //} else { - } + } - //check for snip dialogs -- they have the same name as the command - //TODO better: use the dialog property ! - if( snip[cmd] ){ self.dialogs[cmd] = snip[cmd]; } //deprecated - if( snip.dialog ){ self.dialogs[cmd] = snip.dialog; } + //check for snip dialogs -- they have the same name as the command + //TODO better: use the dialog property ! + if( snip[cmd] ){ self.dialogs[cmd] = snip[cmd]; } //deprecated + if( snip.dialog ){ self.dialogs[cmd] = snip.dialog; } - snips[cmd] = snip; + snips[cmd] = snip; + } catch(e) { + console.debug(e); + } } //console.log(this.keys, this.suggest, this.snip); diff --git a/jspwiki-war/src/main/scripts/wiki/Wiki.js b/jspwiki-war/src/main/scripts/wiki/Wiki.js index f19bfb0a73..ce3c335cc9 100644 --- a/jspwiki-war/src/main/scripts/wiki/Wiki.js +++ b/jspwiki-war/src/main/scripts/wiki/Wiki.js @@ -70,7 +70,14 @@ var Wiki = { wiki.add = behavior.add.bind(behavior); wiki.once = behavior.once.bind(behavior); wiki.update = behavior.update.bind(behavior); - + + setTimeout(function(){ + if (wiki.Snips) { + wiki.Snips.loadPlugins(); + } else { + console.warn("snips are not loaded yet, cannot fetch the plugin list"); + } + //add the standard jspwiki behaviors; needed to render the haddock JSP templates wiki.add( "body", wiki.caniuse ) @@ -170,6 +177,7 @@ var Wiki = { popstate: wiki.popstate, domready: wiki.domready.bind(wiki) }); + }, 500); }, diff --git a/pom.xml b/pom.xml index 9761fa851d..96c43e6e09 100644 --- a/pom.xml +++ b/pom.xml @@ -148,6 +148,7 @@ jspwiki-portable jspwiki-it-tests jspwiki-bom + jspwiki-test-plugin From aaa9b96e4a212512e106ee58f161487b62c427f6 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 23 Oct 2025 17:47:20 -0400 Subject: [PATCH 4/8] Revert "JS{WIKI-1205 adds a java SPI lookup mechanism and a new rest endpoint that provides a list of server installed plugins and alters the UI to support fetching and displaying them." This reverts commit 0df4e224273d8b15274e5da3de4c8a752ea79e93. --- .../org/apache/wiki/api/plugin/Plugin.java | 28 ----- .../wiki/plugin/DefaultPluginManager.java | 20 ---- .../org/apache/wiki/plugin/PluginManager.java | 10 -- .../wiki/search/DefaultSearchManager.java | 76 +----------- .../org/apache/wiki/search/SearchManager.java | 3 - .../src/main/javascript/Wiki.Snips.JSPWiki.js | 111 ++++++------------ .../main/javascript/Wiki.Snips.Markdown.js | 31 +---- jspwiki-portable/build.xml | 7 -- jspwiki-portable/pom.xml | 6 - jspwiki-test-plugin/pom.xml | 21 ---- .../test/plugin/JspwikiTestPlugin.java | 37 ------ .../org.apache.wiki.api.plugin,Plugin | 1 - .../src/main/scripts/jspwiki-common.js | 3 +- .../src/main/scripts/wiki-edit/Snipe.Snips.js | 55 ++++----- jspwiki-war/src/main/scripts/wiki/Wiki.js | 10 +- pom.xml | 1 - 16 files changed, 68 insertions(+), 352 deletions(-) delete mode 100644 jspwiki-test-plugin/pom.xml delete mode 100644 jspwiki-test-plugin/src/main/java/org/apache/jspwiki/jspwiki/test/plugin/JspwikiTestPlugin.java delete mode 100644 jspwiki-test-plugin/src/main/resources/META-INF/services/org.apache.wiki.api.plugin,Plugin diff --git a/jspwiki-api/src/main/java/org/apache/wiki/api/plugin/Plugin.java b/jspwiki-api/src/main/java/org/apache/wiki/api/plugin/Plugin.java index c37cd30d63..950496a41a 100644 --- a/jspwiki-api/src/main/java/org/apache/wiki/api/plugin/Plugin.java +++ b/jspwiki-api/src/main/java/org/apache/wiki/api/plugin/Plugin.java @@ -48,33 +48,5 @@ public interface Plugin { * @throws PluginException In case anything goes wrong. */ String execute( Context context, Map< String, String > params ) throws PluginException; - - /** - * Provides the ability for a plugin to provide a suggestion or template - * for execution within a wiki page. Default returns just the FQCN of the - * plugin, which should enable it to fire off, however no parameters are - * plugin. - * - * Example: com.company.Plugin inputParamter='test' - * - * @since 3.0.0 - * @return String - */ - default String getSnipExample() { - return this.getClass().getCanonicalName(); - } - /** - * Provides the ability for a plugin to provide it's display name that - * is visible via the [{}] autocomplete/suggestion mechanism within the - * editor. - * - * Example: Calls My Custom plugin - * - * @since 3.0.0 - * @return String - */ - default String getDisplayName() { - return this.getClass().getSimpleName(); - } } diff --git a/jspwiki-main/src/main/java/org/apache/wiki/plugin/DefaultPluginManager.java b/jspwiki-main/src/main/java/org/apache/wiki/plugin/DefaultPluginManager.java index 49abf6d4e4..8e082d4406 100644 --- a/jspwiki-main/src/main/java/org/apache/wiki/plugin/DefaultPluginManager.java +++ b/jspwiki-main/src/main/java/org/apache/wiki/plugin/DefaultPluginManager.java @@ -59,16 +59,12 @@ Licensed to the Apache Software Foundation (ASF) under one import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Properties; import java.util.ResourceBundle; -import java.util.ServiceLoader; -import java.util.Set; import java.util.StringTokenizer; -import java.util.logging.Level; /** * Manages plugin classes. There exists a single instance of PluginManager @@ -719,20 +715,4 @@ public Plugin newWikiPlugin( final String pluginName, final ResourceBundle rb ) return plugin; } - @Override - public List getDiscoveredPlugins() { - Collection pluginModules = modules(); - Set plugins = new HashSet<>(); - for(WikiModuleInfo plugin : pluginModules) { - try { - Plugin p = (Plugin) Class.forName(((WikiPluginInfo)plugin).getClassName()).newInstance(); - plugins.add(p); - } catch (Throwable ex) { - LOG.error("failed to load class " + plugin.getName(), ex); - } - } - - return new ArrayList<>(plugins); - } - } diff --git a/jspwiki-main/src/main/java/org/apache/wiki/plugin/PluginManager.java b/jspwiki-main/src/main/java/org/apache/wiki/plugin/PluginManager.java index 552e4c97b9..aa5f752fb1 100644 --- a/jspwiki-main/src/main/java/org/apache/wiki/plugin/PluginManager.java +++ b/jspwiki-main/src/main/java/org/apache/wiki/plugin/PluginManager.java @@ -25,7 +25,6 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.wiki.modules.ModuleManager; import java.io.IOException; -import java.util.List; import java.util.Map; import java.util.ResourceBundle; @@ -130,13 +129,4 @@ public interface PluginManager extends ModuleManager { */ Plugin newWikiPlugin( String pluginName, ResourceBundle rb ) throws PluginException; - /** - * gets a list of plugins available via the java service provider discovery - * mechanism. Helpful for populating autocomplete capabilities. - * - * @since 3.0.0 - * @return list of plugin instances. - */ - List getDiscoveredPlugins(); - } diff --git a/jspwiki-main/src/main/java/org/apache/wiki/search/DefaultSearchManager.java b/jspwiki-main/src/main/java/org/apache/wiki/search/DefaultSearchManager.java index 1d6b8076fe..c31ae6fda1 100644 --- a/jspwiki-main/src/main/java/org/apache/wiki/search/DefaultSearchManager.java +++ b/jspwiki-main/src/main/java/org/apache/wiki/search/DefaultSearchManager.java @@ -54,9 +54,6 @@ Licensed to the Apache Software Foundation (ASF) under one import java.util.Map; import java.util.Properties; import java.util.Set; -import org.apache.wiki.api.plugin.Plugin; -import org.apache.wiki.plugin.PluginManager; -import static org.apache.wiki.search.SearchManager.PLUGIN_SEARCH; /** @@ -83,79 +80,8 @@ public DefaultSearchManager( final Engine engine, final Properties properties ) // TODO: Replace with custom annotations. See JSPWIKI-566 WikiAjaxDispatcherServlet.registerServlet( JSON_SEARCH, new JSONSearch() ); - WikiAjaxDispatcherServlet.registerServlet( PLUGIN_SEARCH, new PluginSearch() ); } - /** - * Provides a JSON AJAX API to the JSPWiki Plugin discovery mechanism, - * primarily used for [{}] based auto complete - */ - public class PluginSearch implements WikiAjaxServlet { - - public static final String AJAX_ACTION_PLUGINS = "plugins"; - public static final int DEFAULT_MAX_RESULTS = 20; - public int maxResults = DEFAULT_MAX_RESULTS; - - /** {@inheritDoc} */ - @Override - public String getServletMapping() { - return PLUGIN_SEARCH; - } - public static class SimpleSnipData { - public String displayName; - public String snip; - } - - /** {@inheritDoc} */ - @Override - public void service( final HttpServletRequest req, - final HttpServletResponse resp, - final String actionName, - final List< String > params ) throws IOException { - String result = "[]"; - String itemId = null; - if( actionName != null && StringUtils.isNotBlank( actionName ) ) { - if( !params.isEmpty() ) { - itemId = params.get( 0 ); - LOG.debug( "itemId=" + itemId ); - if( params.size() > 1 ) { - itemId = params.get( 0 ); - final String maxResultsParam = params.get( 1 ); - LOG.debug( "maxResultsParam=" + maxResultsParam ); - if( StringUtils.isNotBlank( maxResultsParam ) && StringUtils.isNumeric( maxResultsParam ) ) { - maxResults = Integer.parseInt( maxResultsParam ); - } - } - } - - if( actionName.equals( AJAX_ACTION_PLUGINS ) ) { - LOG.debug( "Calling getPlugins() START" ); - PluginManager mgr = m_engine.getManager(PluginManager.class); - final List< Plugin > plugins = mgr.getDiscoveredPlugins(); - List< SimpleSnipData > callResults = new ArrayList<>(); - for (Plugin p : plugins) { - if ( itemId != null && StringUtils.isNotBlank(itemId) ) { - if ( !p.getSnipExample().startsWith(itemId) ) { - continue; - } - } else { - SimpleSnipData data = new SimpleSnipData(); - data.snip = p.getSnipExample(); - data.displayName = p.getDisplayName(); - callResults.add(data); - } - if ( callResults.size() > maxResults ) - break; - } - LOG.debug( "Calling getSuggestions() DONE. " + callResults.size() ); - result = AjaxUtil.toJson( callResults ); - } - } - LOG.debug( "result=" + result ); - resp.getWriter().write( result ); - } - } - /** * Provides a JSON AJAX API to the JSPWiki Search Engine. */ @@ -234,7 +160,7 @@ public List< String > getSuggestions( String wikiName, final int maxLength ) { final String cleanWikiName = MarkupParser.cleanLink(wikiName).toLowerCase() + filename; final String oldStyleName = MarkupParser.wikifyLink(wikiName).toLowerCase() + filename; final Set< String > allPages = m_engine.getManager( ReferenceManager.class ).findCreated(); - + int counter = 0; for( final Iterator< String > i = allPages.iterator(); i.hasNext() && counter < maxLength; ) { final String p = i.next(); diff --git a/jspwiki-main/src/main/java/org/apache/wiki/search/SearchManager.java b/jspwiki-main/src/main/java/org/apache/wiki/search/SearchManager.java index cb241c3aa3..a483212b13 100644 --- a/jspwiki-main/src/main/java/org/apache/wiki/search/SearchManager.java +++ b/jspwiki-main/src/main/java/org/apache/wiki/search/SearchManager.java @@ -44,9 +44,6 @@ public interface SearchManager extends PageFilter, InternalModule, WikiEventList /** The name of the JSON object that manages search. */ String JSON_SEARCH = "search"; - - /** the name of the Plugin discovery endpoint */ - String PLUGIN_SEARCH = "plugins"; /** * Returns the SearchProvider used. diff --git a/jspwiki-main/src/main/javascript/Wiki.Snips.JSPWiki.js b/jspwiki-main/src/main/javascript/Wiki.Snips.JSPWiki.js index 634348ce62..0a5dfbcadf 100644 --- a/jspwiki-main/src/main/javascript/Wiki.Snips.JSPWiki.js +++ b/jspwiki-main/src/main/javascript/Wiki.Snips.JSPWiki.js @@ -44,7 +44,7 @@ Function: snippets */ Wiki.Snips = { - ready: false, + // Snipe predefined commands find: { }, undo: { event: "undo" }, @@ -519,43 +519,41 @@ Wiki.Snips = { //lback: "(^|[^\\[])\\[{([^\\[\\]\\n\\r]*)(?:\\|\\])?$", match: "^([^\\[\\]\\n\\r]*)\\}\\]" }, - pluginDlg: [ Dialog.Selection, - { - caption: "dialog.plugin".localize(), - body: { - "ALLOW {permission} principal ": "Page Access Rights ", - "SET {name}='value'":"Set a Wiki variable", - "${varname}":"Get a Wiki variable", - "If name='{value}' page='pagename' exists='true' contains='regexp'\n\nbody\n":"IF plugin", - "SET keywords={keyword1, keyword2}":"Set Page Keywords", - "SET alias='{pagename}'":"Set Page Alias", - "SET page-styles='prettify-nonum table-condensed-fit'":"Set Page Styles", - "SET sidebar='off'":"Hide Sidebar", - //"Table":"Advanced Tables", - //"Groups":"View all Wiki Groups", - "":"", - "Counter":"Insert a simple counter", - "PageViewPlugin":"Count Views of this page", - "CurrentTimePlugin format='yyyy mmm-dd'":"Insert Current Time", - "Denounce":"Denounce a link", - "Image src='{image.jpg}'":"Insert an Image ", - "IndexPlugin":"Index of all pages", - - "InsertPage page='{pagename}'":"Insert another Page", - "ListLocksPlugin":"List page locks", - "RecentChangesPlugin":"Displays the recent changed pages", - "ReferringPagesPlugin page='{pagename}' separator=',' include='regexp' exclude='regexp'":"Incoming Links (referring pages)", - "ReferredPagesPlugin page='{pagename}' type='local|external|attachment' depth='1..8' include='regexp' exclude='regexp'":"Outgoing Links (referred pages)", - "Search query='{Janne}' max='10'":"Insert a Search query", - "TableOfContents ":"Table Of Contents ", - "UndefinedPagesPlugin":"List pages that are missing", - "UnusedPagesPlugin":"List pages that have been orphaned", - "WeblogArchivePlugin":"Displays a list of older weblog entries", - "WeblogEntryPlugin":"Makes a new weblog entry", - "WeblogPlugin page='{pagename}' startDate='300604' days='30' maxEntries='30' allowComments='false'":"Builds a weblog" - } - } - ] + pluginDlg: [ Dialog.Selection, { + caption: "dialog.plugin".localize(), + body: { + "ALLOW {permission} principal ": "Page Access Rights ", + "SET {name}='value'":"Set a Wiki variable", + "${varname}":"Get a Wiki variable", + "If name='{value}' page='pagename' exists='true' contains='regexp'\n\nbody\n":"IF plugin", + "SET keywords={keyword1, keyword2}":"Set Page Keywords", + "SET alias='{pagename}'":"Set Page Alias", + "SET page-styles='prettify-nonum table-condensed-fit'":"Set Page Styles", + "SET sidebar='off'":"Hide Sidebar", + //"Table":"Advanced Tables", + //"Groups":"View all Wiki Groups", + "":"", + "Counter":"Insert a simple counter", + "PageViewPlugin":"Count Views of this page", + "CurrentTimePlugin format='yyyy mmm-dd'":"Insert Current Time", + "Denounce":"Denounce a link", + "Image src='{image.jpg}'":"Insert an Image ", + "IndexPlugin":"Index of all pages", + + "InsertPage page='{pagename}'":"Insert another Page", + "ListLocksPlugin":"List page locks", + "RecentChangesPlugin":"Displays the recent changed pages", + "ReferringPagesPlugin page='{pagename}' separator=',' include='regexp' exclude='regexp'":"Incoming Links (referring pages)", + "ReferredPagesPlugin page='{pagename}' type='local|external|attachment' depth='1..8' include='regexp' exclude='regexp'":"Outgoing Links (referred pages)", + "Search query='{Janne}' max='10'":"Insert a Search query", + "TableOfContents ":"Table Of Contents ", + "UndefinedPagesPlugin":"List pages that are missing", + "UnusedPagesPlugin":"List pages that have been orphaned", + "WeblogArchivePlugin":"Displays a list of older weblog entries", + "WeblogEntryPlugin":"Makes a new weblog entry", + "WeblogPlugin page='{pagename}' startDate='300604' days='30' maxEntries='30' allowComments='false'":"Builds a weblog" + } + }] }, @@ -630,40 +628,5 @@ Wiki.Snips = { } }] - }, - -//load up any server defined plugins -//note this file is ran through wro4j maven plugin which is limited ES6 support -//thus the usage of super old xhr requests and var vs let. -//see https://github.com/wro4j/wro4j/issues/1178 - - loadPlugins: function(){ - console.info("loading plugin list"); - const pluginDiscoveryRequest2 = new XMLHttpRequest(); - pluginDiscoveryRequest2.open('GET', 'ajax/plugins/plugins', true); // true for asynchronous - pluginDiscoveryRequest2.onload = function() { - if (pluginDiscoveryRequest2.status >= 200 && pluginDiscoveryRequest2.status < 300) { - var data = JSON.parse(pluginDiscoveryRequest2.responseText); - //Wiki.Snips.pluginDlg["TableOfContents "] = "Table Of Contents "; - for (var i=0; i < data.length; i++) { - Wiki.Snips.pluginDlg.pluginDlg[1].body[data[i].snip] = data[i].displayName; - } - Wiki.Snips.ready = true; - console.info("plugin list loaded"); - } else { - console.error('Request failed. Returned status of ' + pluginDiscoveryRequest2.status); - Wiki.Snips.ready = true; - } - }; - pluginDiscoveryRequest2.onerror = function() { - console.error('Network error occurred'); - Wiki.Snips.ready = true; - }; - pluginDiscoveryRequest2.send(); } - - -}; -window.addEventListener("load", function() { - Wiki.Snips.loadPlugins(); -}); \ No newline at end of file +} diff --git a/jspwiki-markdown/src/main/javascript/Wiki.Snips.Markdown.js b/jspwiki-markdown/src/main/javascript/Wiki.Snips.Markdown.js index 94ccd7a0bd..32bc5ce11a 100644 --- a/jspwiki-markdown/src/main/javascript/Wiki.Snips.Markdown.js +++ b/jspwiki-markdown/src/main/javascript/Wiki.Snips.Markdown.js @@ -44,7 +44,7 @@ Function: snippets */ Wiki.Snips = { - ready: false, + // Snipe predefined commands find: { }, undo: { event: "undo" }, @@ -628,32 +628,5 @@ Wiki.Snips = { } }] - }, - - loadPlugins: function(){ - const pluginDiscoveryRequest2 = new XMLHttpRequest(); - pluginDiscoveryRequest2.open('GET', 'ajax/plugins/plugins', true); // true for asynchronous - pluginDiscoveryRequest2.onload = function() { - if (pluginDiscoveryRequest2.status >= 200 && pluginDiscoveryRequest2.status < 300) { - var data = JSON.parse(pluginDiscoveryRequest2.responseText); - //Wiki.Snips.pluginDlg["TableOfContents "] = "Table Of Contents "; - for (var i=0; i < data.length; i++) { - Wiki.Snips.pluginDlg.pluginDlg[1].body[data[i].snip] = data[i].displayName; - } - Wiki.Snips.ready = true; - } else { - console.error('Request failed. Returned status of ' + pluginDiscoveryRequest2.status); - Wiki.Snips.ready = true; - } - }; - pluginDiscoveryRequest2.onerror = function() { - console.error('Network error occurred'); - Wiki.Snips.ready = true; - }; - pluginDiscoveryRequest2.send(); } -}; - -window.addEventListener("load", function() { - Wiki.Snips.loadPlugins(); -}); \ No newline at end of file +} diff --git a/jspwiki-portable/build.xml b/jspwiki-portable/build.xml index cd140f7fe8..1c8fb31215 100644 --- a/jspwiki-portable/build.xml +++ b/jspwiki-portable/build.xml @@ -69,19 +69,12 @@ - - - - - - - diff --git a/jspwiki-portable/pom.xml b/jspwiki-portable/pom.xml index 43367750ff..b675204d54 100644 --- a/jspwiki-portable/pom.xml +++ b/jspwiki-portable/pom.xml @@ -257,12 +257,6 @@ war provided
- - ${project.groupId} - jspwiki-test-plugin - ${project.version} - provided - org.apache.tomcat.embed diff --git a/jspwiki-test-plugin/pom.xml b/jspwiki-test-plugin/pom.xml deleted file mode 100644 index d7f8f4c8fb..0000000000 --- a/jspwiki-test-plugin/pom.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - 4.0.0 - - org.apache.jspwiki - jspwiki-builder - 3.0.0-SNAPSHOT - - jspwiki-test-plugin - jar - - - ${project.groupId} - jspwiki-main - ${project.version} - - - - org.apache.jspwiki.jspwiki.test.plugin.JspwikiTestPlugin - - \ No newline at end of file diff --git a/jspwiki-test-plugin/src/main/java/org/apache/jspwiki/jspwiki/test/plugin/JspwikiTestPlugin.java b/jspwiki-test-plugin/src/main/java/org/apache/jspwiki/jspwiki/test/plugin/JspwikiTestPlugin.java deleted file mode 100644 index 112555ed17..0000000000 --- a/jspwiki-test-plugin/src/main/java/org/apache/jspwiki/jspwiki/test/plugin/JspwikiTestPlugin.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2025 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jspwiki.jspwiki.test.plugin; - -import java.util.Map; -import org.apache.wiki.api.core.Context; -import org.apache.wiki.api.exceptions.PluginException; -import org.apache.wiki.api.plugin.Plugin; - -/** - * a simple hello world test plugin - * - * @author AO - */ -public class JspwikiTestPlugin implements Plugin { - - public JspwikiTestPlugin() { - } - - @Override - public String execute(Context context, Map params) throws PluginException { - return "

HelloWorld

"; - } -} diff --git a/jspwiki-test-plugin/src/main/resources/META-INF/services/org.apache.wiki.api.plugin,Plugin b/jspwiki-test-plugin/src/main/resources/META-INF/services/org.apache.wiki.api.plugin,Plugin deleted file mode 100644 index 80a7487ea4..0000000000 --- a/jspwiki-test-plugin/src/main/resources/META-INF/services/org.apache.wiki.api.plugin,Plugin +++ /dev/null @@ -1 +0,0 @@ -org.apache.jspwiki.jspwiki.test.plugin.JspwikiTestPlugin diff --git a/jspwiki-war/src/main/scripts/jspwiki-common.js b/jspwiki-war/src/main/scripts/jspwiki-common.js index 4e3fa8cd2e..aef3516cd3 100644 --- a/jspwiki-war/src/main/scripts/jspwiki-common.js +++ b/jspwiki-war/src/main/scripts/jspwiki-common.js @@ -52,7 +52,6 @@ Complementary Dynamic Styles (see jspwiki-commonstyles.js) * 270 WikiColumns: dynamic style * 300 Prettify: dynamic style -Note this file gets minimied/compiled into haddock.js */ /* extend mootools */ @@ -70,7 +69,7 @@ String.extend({ }); return text; } -}); +}) // get text of a dhtml node function $getText(el) { diff --git a/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Snips.js b/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Snips.js index 0d92391ec4..fcf8e01ce9 100644 --- a/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Snips.js +++ b/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Snips.js @@ -55,50 +55,47 @@ Snipe.Snips = new Class({ self.suggestions = {}; for( cmd in snips ){ - try{ - snip = $.toFunction( snips[cmd] )( workarea, cmd ); - // short format of snip - if( typeOf(snip) == "string" ){ snip = { snippet:snip }; } + snip = $.toFunction( snips[cmd] )( workarea, cmd ); - //shortcut keys - if(snip.key && (key = snip.key) ){ + // short format of snip + if( typeOf(snip) == "string" ){ snip = { snippet:snip }; } - // key: "f" => "control+f" ; key: "shift+enter" (no change) - if( !key.contains( "+" ) ){ key = control + key; } - self.keys[ key.toLowerCase() ] = cmd; + //shortcut keys + if( (key = snip.key) ){ - } + // key: "f" => "control+f" ; key: "shift+enter" (no change) + if( !key.contains( "+" ) ){ key = control + key; } + self.keys[ key.toLowerCase() ] = cmd; - if( snip.suggest && (suggest = snip.suggest) ){ + } - //this is a suggest snippets - if( typeOf(suggest) == "string" ){ + if( (suggest = snip.suggest) ){ - snip.suggest = { - lback: RegExp( suggest + "$" ), - match: RegExp( "^" + suggest ) - } + //this is a suggest snippets + if( typeOf(suggest) == "string" ){ + snip.suggest = { + lback: RegExp( suggest + "$" ), + match: RegExp( "^" + suggest ) } - self.suggestions[cmd] = snip; - - //otherwise regular snippet - //} else { - } - //check for snip dialogs -- they have the same name as the command - //TODO better: use the dialog property ! - if( snip[cmd] ){ self.dialogs[cmd] = snip[cmd]; } //deprecated - if( snip.dialog ){ self.dialogs[cmd] = snip.dialog; } + self.suggestions[cmd] = snip; + + //otherwise regular snippet + //} else { - snips[cmd] = snip; - } catch(e) { - console.debug(e); } + //check for snip dialogs -- they have the same name as the command + //TODO better: use the dialog property ! + if( snip[cmd] ){ self.dialogs[cmd] = snip[cmd]; } //deprecated + if( snip.dialog ){ self.dialogs[cmd] = snip.dialog; } + + snips[cmd] = snip; + } //console.log(this.keys, this.suggest, this.snip); diff --git a/jspwiki-war/src/main/scripts/wiki/Wiki.js b/jspwiki-war/src/main/scripts/wiki/Wiki.js index ce3c335cc9..f19bfb0a73 100644 --- a/jspwiki-war/src/main/scripts/wiki/Wiki.js +++ b/jspwiki-war/src/main/scripts/wiki/Wiki.js @@ -70,14 +70,7 @@ var Wiki = { wiki.add = behavior.add.bind(behavior); wiki.once = behavior.once.bind(behavior); wiki.update = behavior.update.bind(behavior); - - setTimeout(function(){ - if (wiki.Snips) { - wiki.Snips.loadPlugins(); - } else { - console.warn("snips are not loaded yet, cannot fetch the plugin list"); - } - + //add the standard jspwiki behaviors; needed to render the haddock JSP templates wiki.add( "body", wiki.caniuse ) @@ -177,7 +170,6 @@ var Wiki = { popstate: wiki.popstate, domready: wiki.domready.bind(wiki) }); - }, 500); }, diff --git a/pom.xml b/pom.xml index 96c43e6e09..9761fa851d 100644 --- a/pom.xml +++ b/pom.xml @@ -148,7 +148,6 @@ jspwiki-portable jspwiki-it-tests jspwiki-bom - jspwiki-test-plugin From 198adc856af00de630e44761c7c8f94b5a13a096 Mon Sep 17 00:00:00 2001 From: Alex O'Ree Date: Fri, 7 Nov 2025 16:18:00 -0500 Subject: [PATCH 5/8] JSPWIKI-1205 adds additional safe guards for the file upload changes --- .../apache/wiki/attachment/AttachmentServlet.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java b/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java index b849b7a5c3..dc99003837 100644 --- a/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java +++ b/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java @@ -103,6 +103,8 @@ public class AttachmentServlet extends HttpServlet { /** * Initializes the servlet from Engine properties. + * @param config + * @throws jakarta.servlet.ServletException */ @Override public void init( final ServletConfig config ) throws ServletException { @@ -400,7 +402,16 @@ protected String upload( final HttpServletRequest req ) throws RedirectException final UploadListener pl = new UploadListener(); m_engine.getManager( ProgressManager.class ).startProgress( pl, progressId ); - + if ("chunked".equalsIgnoreCase(req.getHeader("Transfer-Encoding"))) { + //not sure how chunked encoding would work here, this should block it + //this is to prevent resource exhaustion + throw new RedirectException("Chunked encoding is not allowed for this service", nextPage); + } + if (req.getContentLengthLong() > m_maxSize) { + //we don't want total upload size to be larger than the max + //this is to prevent resource exhaustion + throw new RedirectException("Too big " +req.getContentLengthLong() + " vs " + m_maxSize, nextPage); + } final JakartaServletFileUpload upload = new JakartaServletFileUpload( factory ); upload.setHeaderCharset(StandardCharsets.UTF_8); upload.setProgressListener( pl ); From 809e7e04a205c7a429107cf21aa9ccd0a766e173 Mon Sep 17 00:00:00 2001 From: Alex O'Ree Date: Fri, 7 Nov 2025 17:38:41 -0500 Subject: [PATCH 6/8] JSP{WIKI-1205 adds more robust error handling. File attachment uploads now redirect correctly and show the too big error message in Error.jsp --- .../wiki/attachment/AttachmentServlet.java | 24 +++++++++++++++---- jspwiki-war/src/main/webapp/Error.jsp | 17 ++++++++----- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java b/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java index dc99003837..1a73ecc1d2 100644 --- a/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java +++ b/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java @@ -61,6 +61,7 @@ Licensed to the Apache Software Foundation (ASF) under one import jakarta.servlet.ServletConfig; import jakarta.servlet.ServletContext; import jakarta.servlet.ServletException; +import jakarta.servlet.ServletInputStream; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -352,7 +353,17 @@ public void doPost( final HttpServletRequest req, final HttpServletResponse res } catch( final RedirectException e ) { final Session session = Wiki.session().find( m_engine, req ); session.addMessage( e.getMessage() ); - + //drain the request body + try (ServletInputStream inputStream = req.getInputStream();) { + int data; + while ((data = inputStream.read()) != -1) { + //we are just reading the stream to the end + } + } catch (Exception err) { + //ignore it + } + + req.getSession().setAttribute("msg", e.getMessage()); res.sendRedirect( e.getRedirect() ); } @@ -376,6 +387,8 @@ private String validateNextPage( String nextPage, final String errorPage ) { /** * Uploads a specific mime multipart input set, intercepts exceptions. + * + * If the total request size is too big, the user will be redirected to the Error.jsp page * * @param req The servlet request * @return The page to which we should go next. @@ -405,12 +418,13 @@ protected String upload( final HttpServletRequest req ) throws RedirectException if ("chunked".equalsIgnoreCase(req.getHeader("Transfer-Encoding"))) { //not sure how chunked encoding would work here, this should block it //this is to prevent resource exhaustion - throw new RedirectException("Chunked encoding is not allowed for this service", nextPage); + + throw new RedirectException("Chunked encoding is not allowed for this service", errorPage +"?Error=true"); } if (req.getContentLengthLong() > m_maxSize) { //we don't want total upload size to be larger than the max //this is to prevent resource exhaustion - throw new RedirectException("Too big " +req.getContentLengthLong() + " vs " + m_maxSize, nextPage); + throw new RedirectException("Request too big" +req.getContentLengthLong() + " vs " + m_maxSize + " bytes", errorPage +"?Error=true"); } final JakartaServletFileUpload upload = new JakartaServletFileUpload( factory ); upload.setHeaderCharset(StandardCharsets.UTF_8); @@ -419,7 +433,7 @@ protected String upload( final HttpServletRequest req ) throws RedirectException try { items = upload.parseRequest(req); } catch (FileUploadByteCountLimitException ex) { - throw new RedirectException( "Too big " + ex.getMessage(), nextPage ); + throw new RedirectException( "Request too big " + ex.getMessage(), nextPage ); } String wikipage = null; String changeNote = null; @@ -459,7 +473,7 @@ protected String upload( final HttpServletRequest req ) throws RedirectException for( final FileItem actualFile : fileItems ) { if( !context.hasAdminPermissions() ) { if (actualFile.getSize()> m_maxSize) { - throw new RedirectException("Too big " + actualFile.getName() + " " + actualFile.getSize() + " vs " + m_maxSize, nextPage); + throw new RedirectException("Attachment too big " + actualFile.getName() + " " + actualFile.getSize() + " vs " + m_maxSize + " bytes", nextPage); } } diff --git a/jspwiki-war/src/main/webapp/Error.jsp b/jspwiki-war/src/main/webapp/Error.jsp index c020cd208a..c9625eccc5 100644 --- a/jspwiki-war/src/main/webapp/Error.jsp +++ b/jspwiki-war/src/main/webapp/Error.jsp @@ -32,15 +32,20 @@ <% Engine wiki = Wiki.engine().find( getServletConfig() ); Context wikiContext = Wiki.context().create( wiki, request, ContextEnum.WIKI_ERROR.getRequestContext() ); + //the following line is critical to get the jspwiki jsp tags to work + pageContext.setAttribute( Context.ATTR_CONTEXT, wikiContext, PageContext.REQUEST_SCOPE); String pagereq = wikiContext.getName(); response.setContentType("text/html; charset="+wiki.getContentEncoding() ); String msg = "An unknown error was caught by Error.jsp"; - + if ("true".equalsIgnoreCase(request.getParameter("Error"))) { + //this is coming from the attaching upload servlet + msg = (String) request.getSession().getAttribute("msg"); + } Throwable realcause = null; - - msg = exception.getMessage(); + if (exception!=null) + msg = exception.getMessage(); if( msg == null || msg.isEmpty()) { msg = "An unknown exception "+exception.getClass().getName()+" was caught by Error.jsp."; @@ -52,7 +57,7 @@ // imported in JSP pages. // - if( exception instanceof jakarta.servlet.jsp.JspException ) + if( exception!=null && exception instanceof jakarta.servlet.jsp.JspException ) { log.debug("IS JSPEXCEPTION"); realcause = ((jakarta.servlet.jsp.JspException)exception).getCause(); @@ -82,9 +87,9 @@
Exception
-
<%=realcause.getClass().getName()%>
+
<%=realcause!=null ? realcause.getClass().getName() : ""%>
Place where detected
-
<%=FileUtil.getThrowingMethod(realcause)%>
+
<%=realcause!=null ? FileUtil.getThrowingMethod(realcause) : ""%>

If you have changed the templates, please do check them. This error message From f85bd629bb26943d92aa093bbe854888b8a8ced0 Mon Sep 17 00:00:00 2001 From: Alex O'Ree Date: Sun, 16 Nov 2025 14:57:10 -0500 Subject: [PATCH 7/8] JSPWIKI-1205 adds the maximum attachment file size to the user interface --- .../wiki/attachment/AttachmentServlet.java | 13 +++- .../org/apache/wiki/tags/MaxUploadTag.java | 66 +++++++++++++++++++ .../src/main/resources/META-INF/jspwiki.tld | 6 ++ .../resources/templates/default.properties | 1 + .../resources/templates/default_de.properties | 1 + .../resources/templates/default_es.properties | 3 +- .../resources/templates/default_fi.properties | 1 + .../resources/templates/default_fr.properties | 1 + .../resources/templates/default_it.properties | 1 + .../resources/templates/default_nl.properties | 1 + .../templates/default_pt_BR.properties | 1 + .../resources/templates/default_ru.properties | 1 + .../templates/default_zh_CN.properties | 1 + .../templates/default/AttachmentTab.jsp | 6 +- 14 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 jspwiki-main/src/main/java/org/apache/wiki/tags/MaxUploadTag.java diff --git a/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java b/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java index dba1eece5f..1384d20095 100644 --- a/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java +++ b/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java @@ -67,6 +67,7 @@ Licensed to the Apache Software Foundation (ASF) under one import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.fileupload2.core.FileUploadByteCountLimitException; import java.util.ResourceBundle; +import org.apache.wiki.tags.MaxUploadTag; /** @@ -421,13 +422,16 @@ protected String upload( final HttpServletRequest req ) throws RedirectException if ("chunked".equalsIgnoreCase(req.getHeader("Transfer-Encoding"))) { //not sure how chunked encoding would work here, this should block it //this is to prevent resource exhaustion - + //TODO i18n this error message throw new RedirectException("Chunked encoding is not allowed for this service", errorPage +"?Error=true"); } if (req.getContentLengthLong() > m_maxSize) { //we don't want total upload size to be larger than the max //this is to prevent resource exhaustion - throw new RedirectException("Request too big" +req.getContentLengthLong() + " vs " + m_maxSize + " bytes", errorPage +"?Error=true"); + //TODO i18n this error message + throw new RedirectException("Request too big " + + MaxUploadTag.humanReadableByteCountBin(req.getContentLengthLong()) + " vs " + + MaxUploadTag.humanReadableByteCountBin(m_maxSize), errorPage +"?Error=true"); } final JakartaServletFileUpload upload = new JakartaServletFileUpload( factory ); upload.setHeaderCharset(StandardCharsets.UTF_8); @@ -476,7 +480,10 @@ protected String upload( final HttpServletRequest req ) throws RedirectException for( final FileItem actualFile : fileItems ) { if( !context.hasAdminPermissions() ) { if (actualFile.getSize()> m_maxSize) { - throw new RedirectException("Attachment too big " + actualFile.getName() + " " + actualFile.getSize() + " vs " + m_maxSize + " bytes", nextPage); + //TODO i18n this error message + throw new RedirectException("Attachment too big " + actualFile.getName() + " " + + MaxUploadTag.humanReadableByteCountBin(actualFile.getSize()) + " vs " + + MaxUploadTag.humanReadableByteCountBin(m_maxSize), nextPage); } } diff --git a/jspwiki-main/src/main/java/org/apache/wiki/tags/MaxUploadTag.java b/jspwiki-main/src/main/java/org/apache/wiki/tags/MaxUploadTag.java new file mode 100644 index 0000000000..7d787cfc34 --- /dev/null +++ b/jspwiki-main/src/main/java/org/apache/wiki/tags/MaxUploadTag.java @@ -0,0 +1,66 @@ +/* + * Copyright 2025 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wiki.tags; + +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.wiki.util.TextUtil; + +/** + * Outputs the server's configured maximum file upload size. + * + * @since 3.0.0 + */ +public class MaxUploadTag extends WikiTagBase { + + private static final Logger LOG = LogManager.getLogger(MaxUploadTag.class); + + @Override + public int doWikiStartTag() throws Exception { + String maxUploadSize = m_wikiContext.getEngine().getWikiProperties().getProperty("jspwiki.attachment.maxsize"); + if (maxUploadSize != null) { + try { + long bytes = Long.parseLong(maxUploadSize); + String humanFormat = humanReadableByteCountBin(bytes); + pageContext.getOut().print(TextUtil.replaceEntities(humanFormat)); + } catch (NumberFormatException ex) { + LOG.warn("Parse error from configuration setting jspwiki.attachment.maxsize " + ex.getMessage()); + } + } + return SKIP_BODY; + } + + /* + Binary (1 Ki = 1,024) + from https://stackoverflow.com/a/3758880/1203182 + */ + public static String humanReadableByteCountBin(long bytes) { + long absB = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes); + if (absB < 1024) { + return bytes + " B"; + } + long value = absB; + CharacterIterator ci = new StringCharacterIterator("KMGTPE"); + for (int i = 40; i >= 0 && absB > 0xfffccccccccccccL >> i; i -= 10) { + value >>= 10; + ci.next(); + } + value *= Long.signum(bytes); + return String.format("%.1f %ciB", value / 1024.0, ci.current()); + } +} diff --git a/jspwiki-main/src/main/resources/META-INF/jspwiki.tld b/jspwiki-main/src/main/resources/META-INF/jspwiki.tld index 7507d0d26b..bf867ff917 100644 --- a/jspwiki-main/src/main/resources/META-INF/jspwiki.tld +++ b/jspwiki-main/src/main/resources/META-INF/jspwiki.tld @@ -872,4 +872,10 @@ true + + + MaxUpload + org.apache.wiki.tags.MaxUploadTag + JSP + diff --git a/jspwiki-main/src/main/resources/templates/default.properties b/jspwiki-main/src/main/resources/templates/default.properties index 33537fc726..1f81ab30c2 100644 --- a/jspwiki-main/src/main/resources/templates/default.properties +++ b/jspwiki-main/src/main/resources/templates/default.properties @@ -36,6 +36,7 @@ attach.add.info=In order to upload a new attachment to this page, please use the attach.add.permission=Only authorized users are allowed to upload new attachments. attach.bytes=bytes attach.add.selectfile=Select file: +attach.add.maxUpload=Max upload size: attach.add.changenote=Change Note: attach.add.submit=Upload attach.add.select=Select files or drop them here diff --git a/jspwiki-main/src/main/resources/templates/default_de.properties b/jspwiki-main/src/main/resources/templates/default_de.properties index aeb3da49bd..f115eab38c 100644 --- a/jspwiki-main/src/main/resources/templates/default_de.properties +++ b/jspwiki-main/src/main/resources/templates/default_de.properties @@ -742,3 +742,4 @@ javascript.tip.default.title=Weitere... javascript.prefs.areyousure=Wenn du nicht auf 'Benutzereinstellungen speichern' klickst, \ werden deine Einstellungen verworfen. Bist du sicher, dass diese Seite verlassen werden soll? +attach.add.maxUpload=Maximale Uploadgr\u00f6\u00dfe: diff --git a/jspwiki-main/src/main/resources/templates/default_es.properties b/jspwiki-main/src/main/resources/templates/default_es.properties index 89a7f01011..27beb72f4f 100644 --- a/jspwiki-main/src/main/resources/templates/default_es.properties +++ b/jspwiki-main/src/main/resources/templates/default_es.properties @@ -698,4 +698,5 @@ javascript.dialog.plugin = Plugin javascript.dialog.principal = Roles, Grupos o Usuarios javascript.dialog.styles = Estilos adicionales javascript.dialog.toc.options = opciones de la Tabla de Contenidos -javascript.preview.zone = Zona de previsualizaci\u00f3n \ No newline at end of file +javascript.preview.zone = Zona de previsualizaci\u00f3n +attach.add.maxUpload=Tama\u00f1o m\u00e1ximo de carga: diff --git a/jspwiki-main/src/main/resources/templates/default_fi.properties b/jspwiki-main/src/main/resources/templates/default_fi.properties index 18790a7a3d..253d92d142 100644 --- a/jspwiki-main/src/main/resources/templates/default_fi.properties +++ b/jspwiki-main/src/main/resources/templates/default_fi.properties @@ -707,3 +707,4 @@ notification.createUserProfile.accept.subject=Tervetuloa {0}:aan info.keywords=Avainsanat: {0} notification.createUserProfile.accept.content=Onnittelut! Uusi profiilisi {0}:ssa on luotu. Profiilisi tiedot ovat seuraavat: \n\nKirjautumisnimi: \ {1} \nNimesi: {2} \nS\u00e4hk\u00f6posti: {3} \n\nJos unohdat salasanasi, voit palauttaa sen osoitteessa {4} +attach.add.maxUpload=Suurin l\u00e4hetyskoko: diff --git a/jspwiki-main/src/main/resources/templates/default_fr.properties b/jspwiki-main/src/main/resources/templates/default_fr.properties index d0259660e4..5e34306a6e 100644 --- a/jspwiki-main/src/main/resources/templates/default_fr.properties +++ b/jspwiki-main/src/main/resources/templates/default_fr.properties @@ -748,3 +748,4 @@ javascript.tip.default.title=Plus... javascript.prefs.areyousure=Si vous ne cliquez pas sur le bouton 'Enregistrer les pr\u00e9f\u00e9rences utilisateur', \ vos changements seront perdus. Etes-vous s\u00fbr de vouloir quitter cette page\u00a0? +attach.add.maxUpload=Taille maximale de t\u00e9l\u00e9chargement\u00a0: diff --git a/jspwiki-main/src/main/resources/templates/default_it.properties b/jspwiki-main/src/main/resources/templates/default_it.properties index 174580b375..ae836ff0b1 100644 --- a/jspwiki-main/src/main/resources/templates/default_it.properties +++ b/jspwiki-main/src/main/resources/templates/default_it.properties @@ -736,3 +736,4 @@ prefs.user.pagecookies.actions = Azioni javascript.dialog.character.entities = Entit\u00e0 dei caratteri prefs.password0 = Password attuale * userbox.button = Menu utente +attach.add.maxUpload=Dimensione massima di caricamento: diff --git a/jspwiki-main/src/main/resources/templates/default_nl.properties b/jspwiki-main/src/main/resources/templates/default_nl.properties index 212309bef1..5f020c41c4 100644 --- a/jspwiki-main/src/main/resources/templates/default_nl.properties +++ b/jspwiki-main/src/main/resources/templates/default_nl.properties @@ -737,3 +737,4 @@ javascript.dialog.styles = Extra Stijlen javascript.dialog.toc.options = TOC-opties prefs.password0 = Huidig Wachtwoord * javascript.dialog.plugin = Plug-in +attach.add.maxUpload=Maximale uploadgrootte: diff --git a/jspwiki-main/src/main/resources/templates/default_pt_BR.properties b/jspwiki-main/src/main/resources/templates/default_pt_BR.properties index 77116a5eda..d5cad82f9c 100644 --- a/jspwiki-main/src/main/resources/templates/default_pt_BR.properties +++ b/jspwiki-main/src/main/resources/templates/default_pt_BR.properties @@ -682,3 +682,4 @@ javascript.slimbox.previous=«Anterior javascript.slimbox.btn=Clique para visualizar {0} javascript.slimbox.size=Tamanho: {0}px x {1}px javascript.tip.default.title=Mais... +attach.add.maxUpload=Tamanho m\u00e1ximo de upload: diff --git a/jspwiki-main/src/main/resources/templates/default_ru.properties b/jspwiki-main/src/main/resources/templates/default_ru.properties index 8388cd24f4..4c2db69489 100644 --- a/jspwiki-main/src/main/resources/templates/default_ru.properties +++ b/jspwiki-main/src/main/resources/templates/default_ru.properties @@ -722,3 +722,4 @@ javascript.filter.hint=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0448\u0430\u javascript.tablefilter=\u0424\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b javascript.slimbox.caption=\u041f\u0440\u044f\u043c\u0430\u044f \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 {0} javascript.slimbox.btn=\u041d\u0430\u0436\u043c\u0438\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c {0} +attach.add.maxUpload=\u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u0430\u0437\u043c\u0435\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438: diff --git a/jspwiki-main/src/main/resources/templates/default_zh_CN.properties b/jspwiki-main/src/main/resources/templates/default_zh_CN.properties index 03bcc41ec0..81e8c491f1 100644 --- a/jspwiki-main/src/main/resources/templates/default_zh_CN.properties +++ b/jspwiki-main/src/main/resources/templates/default_zh_CN.properties @@ -723,3 +723,4 @@ attach.add.drop = \u6216\u62d6\u653e\u5230\u6b64\u5904! sbox.search.button = \u5feb\u9012\u641c\u7d22\u83dc\u5355 javascript.dialog.principal = \u89d2\u8272\u3001\u7fa4\u7ec4\u6216\u7528\u6237 prefs.user.pagecookies.actions = \u64cd\u4f5c +attach.add.maxUpload=\u6700\u5927\u4e0a\u4f20\u5927\u5c0f: diff --git a/jspwiki-war/src/main/webapp/templates/default/AttachmentTab.jsp b/jspwiki-war/src/main/webapp/templates/default/AttachmentTab.jsp index cb56e01c06..5c734a2b9f 100644 --- a/jspwiki-war/src/main/webapp/templates/default/AttachmentTab.jsp +++ b/jspwiki-war/src/main/webapp/templates/default/AttachmentTab.jsp @@ -53,7 +53,11 @@ <%--

--%>
- +
  • From 6e3e29e9c2b27756eccc650e9acb2e49b17c6079 Mon Sep 17 00:00:00 2001 From: Alex O'Ree Date: Sat, 22 Nov 2025 21:03:57 -0500 Subject: [PATCH 8/8] JSPWIKI-1205 removes the chunked encoded check as it's not relevant --- .../java/org/apache/wiki/attachment/AttachmentServlet.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java b/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java index 1384d20095..961c93d460 100644 --- a/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java +++ b/jspwiki-main/src/main/java/org/apache/wiki/attachment/AttachmentServlet.java @@ -419,12 +419,7 @@ protected String upload( final HttpServletRequest req ) throws RedirectException final UploadListener pl = new UploadListener(); m_engine.getManager( ProgressManager.class ).startProgress( pl, progressId ); - if ("chunked".equalsIgnoreCase(req.getHeader("Transfer-Encoding"))) { - //not sure how chunked encoding would work here, this should block it - //this is to prevent resource exhaustion - //TODO i18n this error message - throw new RedirectException("Chunked encoding is not allowed for this service", errorPage +"?Error=true"); - } + if (req.getContentLengthLong() > m_maxSize) { //we don't want total upload size to be larger than the max //this is to prevent resource exhaustion