From 0f043f14b5fb1e6d1f85cc6e659a80cb60f8c85e Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Thu, 8 May 2025 10:13:27 +0200 Subject: [PATCH 1/4] Allow releasing bound objects via HTTP --- .../java/org/kohsuke/stapler/RequestImpl.java | 1 + .../org/kohsuke/stapler/StaplerRequest.java | 8 +++--- .../org/kohsuke/stapler/StaplerRequest2.java | 4 ++- .../java/org/kohsuke/stapler/bind/Bound.java | 7 +++++ .../stapler/bind/BoundObjectTable.java | 27 +++++++++++++++++++ 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/kohsuke/stapler/RequestImpl.java b/core/src/main/java/org/kohsuke/stapler/RequestImpl.java index f97c52b06..61a4ffe4b 100644 --- a/core/src/main/java/org/kohsuke/stapler/RequestImpl.java +++ b/core/src/main/java/org/kohsuke/stapler/RequestImpl.java @@ -216,6 +216,7 @@ public RenderOnDemandParameters createJavaScriptProxyParameters(Object toBeExpor return new RenderOnDemandParameters( "makeStaplerProxy", bound.getURL(), + bound.getReleaseURL(), getWebApp().getCrumbIssuer().issueCrumb(), bound.getBoundJavaScriptUrlNames()); } diff --git a/core/src/main/java/org/kohsuke/stapler/StaplerRequest.java b/core/src/main/java/org/kohsuke/stapler/StaplerRequest.java index 0c0ea358b..bf751cd23 100644 --- a/core/src/main/java/org/kohsuke/stapler/StaplerRequest.java +++ b/core/src/main/java/org/kohsuke/stapler/StaplerRequest.java @@ -571,12 +571,14 @@ public interface StaplerRequest extends HttpServletRequest { final class RenderOnDemandParameters { public final String proxyMethod; public final String url; + public final String releaseUrl; public final String crumb; public final Set urlNames; - public RenderOnDemandParameters(String proxyMethod, String url, String crumb, Set urlNames) { + public RenderOnDemandParameters(String proxyMethod, String url, String releaseUrl, String crumb, Set urlNames) { this.proxyMethod = proxyMethod; this.url = url; + this.releaseUrl = releaseUrl; this.crumb = crumb; this.urlNames = urlNames; } @@ -998,7 +1000,7 @@ public String createJavaScriptProxy(Object toBeExported) { @Override public RenderOnDemandParameters createJavaScriptProxyParameters(Object toBeExported) { StaplerRequest.RenderOnDemandParameters result = from.createJavaScriptProxyParameters(toBeExported); - return new RenderOnDemandParameters(result.proxyMethod, result.url, result.crumb, result.urlNames); + return new RenderOnDemandParameters(result.proxyMethod, result.url, result.releaseUrl, result.crumb, result.urlNames); } @Override @@ -1654,7 +1656,7 @@ public String createJavaScriptProxy(Object toBeExported) { @Override public RenderOnDemandParameters createJavaScriptProxyParameters(Object toBeExported) { StaplerRequest2.RenderOnDemandParameters result = from.createJavaScriptProxyParameters(toBeExported); - return new RenderOnDemandParameters(result.proxyMethod, result.crumb, result.url, result.urlNames); + return new RenderOnDemandParameters(result.proxyMethod, result.crumb, result.url, result.releaseUrl, result.urlNames); } @Override diff --git a/core/src/main/java/org/kohsuke/stapler/StaplerRequest2.java b/core/src/main/java/org/kohsuke/stapler/StaplerRequest2.java index 91b4eb996..c27599623 100644 --- a/core/src/main/java/org/kohsuke/stapler/StaplerRequest2.java +++ b/core/src/main/java/org/kohsuke/stapler/StaplerRequest2.java @@ -533,12 +533,14 @@ public interface StaplerRequest2 extends HttpServletRequest { final class RenderOnDemandParameters { public final String proxyMethod; public final String url; + public final String releaseUrl; public final String crumb; public final Set urlNames; - public RenderOnDemandParameters(String proxyMethod, String url, String crumb, Set urlNames) { + public RenderOnDemandParameters(String proxyMethod, String url, String releaseUrl, String crumb, Set urlNames) { this.proxyMethod = proxyMethod; this.url = url; + this.releaseUrl = releaseUrl; this.crumb = crumb; this.urlNames = urlNames; } diff --git a/core/src/main/java/org/kohsuke/stapler/bind/Bound.java b/core/src/main/java/org/kohsuke/stapler/bind/Bound.java index fabbef659..3d8baaf26 100644 --- a/core/src/main/java/org/kohsuke/stapler/bind/Bound.java +++ b/core/src/main/java/org/kohsuke/stapler/bind/Bound.java @@ -54,6 +54,13 @@ public abstract class Bound implements HttpResponse { */ public abstract String getURL(); + /** + * The URL where the object can be released, or {@code null} if not applicable. + */ + public String getReleaseURL() { + return null; + } + /** * Gets the bound object. */ diff --git a/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java b/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java index 55eda3dc3..9b0022aef 100644 --- a/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java +++ b/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java @@ -75,6 +75,27 @@ public static boolean isValidJavaIdentifier(String name) { .allMatch(it -> Character.isJavaIdentifierPart(it) && !Character.isIdentifierIgnorable(it) && it < 256); } + /** + * Explicitly unbind this object via HTTP. + * + * @throws HttpResponses.HttpResponseException expected outcome returning 200 OK + */ + public void doRelease(StaplerRequest2 req, StaplerResponse2 rsp) throws HttpResponses.HttpResponseException, IOException { + final Table table = resolve(false); + if (table == null) { + rsp.sendError(404); + } + + String id = req.getRestOfPath().replace("/", ""); + + Object object = table.resolve(id); + if (object == null) { + rsp.sendError(200); + } + table.release(id); + rsp.sendError(200); + } + /** * This serves the script content for a bound object. Support CSP-compatible st:bind and similar methods of making * objects accessible to JS. @@ -238,6 +259,11 @@ public void release() { Table.this.release(id); } + @Override + public String getReleaseURL() { + return Stapler.getCurrentRequest2().getContextPath() + RELEASE_PREFIX + id; + } + @Override public String getURL() { return Stapler.getCurrentRequest2().getContextPath() + PREFIX + id; @@ -374,6 +400,7 @@ private Object writeReplace() { } public static final String PREFIX = "/$stapler/bound/"; + public static final String RELEASE_PREFIX = "/$stapler/bound/release/"; static final String SCRIPT_PREFIX = "/$stapler/bound/script"; /** From f61fcbbb7873460678c98e4ac3dffd7160be493a Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Thu, 8 May 2025 10:23:27 +0200 Subject: [PATCH 2/4] Thanks Spotless --- .../main/java/org/kohsuke/stapler/StaplerRequest.java | 9 ++++++--- .../main/java/org/kohsuke/stapler/StaplerRequest2.java | 3 ++- .../java/org/kohsuke/stapler/bind/BoundObjectTable.java | 3 ++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/kohsuke/stapler/StaplerRequest.java b/core/src/main/java/org/kohsuke/stapler/StaplerRequest.java index bf751cd23..86c4b383b 100644 --- a/core/src/main/java/org/kohsuke/stapler/StaplerRequest.java +++ b/core/src/main/java/org/kohsuke/stapler/StaplerRequest.java @@ -575,7 +575,8 @@ final class RenderOnDemandParameters { public final String crumb; public final Set urlNames; - public RenderOnDemandParameters(String proxyMethod, String url, String releaseUrl, String crumb, Set urlNames) { + public RenderOnDemandParameters( + String proxyMethod, String url, String releaseUrl, String crumb, Set urlNames) { this.proxyMethod = proxyMethod; this.url = url; this.releaseUrl = releaseUrl; @@ -1000,7 +1001,8 @@ public String createJavaScriptProxy(Object toBeExported) { @Override public RenderOnDemandParameters createJavaScriptProxyParameters(Object toBeExported) { StaplerRequest.RenderOnDemandParameters result = from.createJavaScriptProxyParameters(toBeExported); - return new RenderOnDemandParameters(result.proxyMethod, result.url, result.releaseUrl, result.crumb, result.urlNames); + return new RenderOnDemandParameters( + result.proxyMethod, result.url, result.releaseUrl, result.crumb, result.urlNames); } @Override @@ -1656,7 +1658,8 @@ public String createJavaScriptProxy(Object toBeExported) { @Override public RenderOnDemandParameters createJavaScriptProxyParameters(Object toBeExported) { StaplerRequest2.RenderOnDemandParameters result = from.createJavaScriptProxyParameters(toBeExported); - return new RenderOnDemandParameters(result.proxyMethod, result.crumb, result.url, result.releaseUrl, result.urlNames); + return new RenderOnDemandParameters( + result.proxyMethod, result.crumb, result.url, result.releaseUrl, result.urlNames); } @Override diff --git a/core/src/main/java/org/kohsuke/stapler/StaplerRequest2.java b/core/src/main/java/org/kohsuke/stapler/StaplerRequest2.java index c27599623..f816f2ac5 100644 --- a/core/src/main/java/org/kohsuke/stapler/StaplerRequest2.java +++ b/core/src/main/java/org/kohsuke/stapler/StaplerRequest2.java @@ -537,7 +537,8 @@ final class RenderOnDemandParameters { public final String crumb; public final Set urlNames; - public RenderOnDemandParameters(String proxyMethod, String url, String releaseUrl, String crumb, Set urlNames) { + public RenderOnDemandParameters( + String proxyMethod, String url, String releaseUrl, String crumb, Set urlNames) { this.proxyMethod = proxyMethod; this.url = url; this.releaseUrl = releaseUrl; diff --git a/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java b/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java index 9b0022aef..554a9e218 100644 --- a/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java +++ b/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java @@ -80,7 +80,8 @@ public static boolean isValidJavaIdentifier(String name) { * * @throws HttpResponses.HttpResponseException expected outcome returning 200 OK */ - public void doRelease(StaplerRequest2 req, StaplerResponse2 rsp) throws HttpResponses.HttpResponseException, IOException { + public void doRelease(StaplerRequest2 req, StaplerResponse2 rsp) + throws HttpResponses.HttpResponseException, IOException { final Table table = resolve(false); if (table == null) { rsp.sendError(404); From 7a948610b19330363b24ee2c969464c3d1f95b7d Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Fri, 9 May 2025 11:24:03 +0200 Subject: [PATCH 3/4] Add early returns after change from HttpResponseException --- .../main/java/org/kohsuke/stapler/bind/BoundObjectTable.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java b/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java index 554a9e218..dab95a4d9 100644 --- a/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java +++ b/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java @@ -85,6 +85,7 @@ public void doRelease(StaplerRequest2 req, StaplerResponse2 rsp) final Table table = resolve(false); if (table == null) { rsp.sendError(404); + return; } String id = req.getRestOfPath().replace("/", ""); @@ -92,6 +93,7 @@ public void doRelease(StaplerRequest2 req, StaplerResponse2 rsp) Object object = table.resolve(id); if (object == null) { rsp.sendError(200); + return; } table.release(id); rsp.sendError(200); From da77af49cf7edb5d37284ff629c3f3b2ac8c09b7 Mon Sep 17 00:00:00 2001 From: Daniel Beck <1831569+daniel-beck@users.noreply.github.com> Date: Mon, 22 Sep 2025 10:31:12 +0200 Subject: [PATCH 4/4] fix merge conflict --- .../src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java b/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java index 70718dca5..2887801d4 100644 --- a/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java +++ b/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java @@ -36,6 +36,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.kohsuke.stapler.Ancestor; +import org.kohsuke.stapler.HttpResponses; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.StaplerFallback;