Skip to content

Commit b13cdd7

Browse files
KasinhouMatus Kasakclaude
authored
Return empty feed instead of 204 from the DiscoJuice feeds endpoint (#1422)
* Return empty feed instead of 204 from the DiscoJuice feeds endpoint When no discofeed content is cached — the default, since `shibboleth.discofeed.allowed` is off — `/api/discojuice/feeds` responded with `204 No Content`. The DiscoJuice IdP-discovery widget on the login and register pages loads this endpoint via JSONP and passes the body straight to `jQuery.merge()`. An empty body leaves the callback argument undefined, so the widget throws `TypeError: Cannot read properties of undefined (reading 'length')` on every default deployment. Respond with an empty but valid feed instead: `callback([])` when a callback is given, `[]` otherwise. The JSONP callback then always fires with a well-formed array and the widget no longer crashes; deployments with feeds enabled are unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Shorten the empty-feed comment Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Matus Kasak <matus.kasak@dataquest.sk> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 2a1b41b commit b13cdd7

2 files changed

Lines changed: 31 additions & 7 deletions

File tree

dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinDiscoJuiceFeedsController.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99

1010
import static org.springframework.web.bind.annotation.RequestMethod.GET;
1111

12-
import java.io.IOException;
13-
14-
import jakarta.servlet.http.HttpServletResponse;
1512
import org.apache.commons.lang3.StringUtils;
1613
import org.apache.logging.log4j.Logger;
1714
import org.dspace.app.rest.ClarinDiscoJuiceFeedsDownloadService;
@@ -45,13 +42,13 @@ public class ClarinDiscoJuiceFeedsController {
4542

4643
@RequestMapping(method = GET, produces = APPLICATION_JAVASCRIPT_UTF8)
4744
@PreAuthorize("permitAll()")
48-
public ResponseEntity getDiscojuiceFeeds(@RequestParam(value = "callback", required = false) String callback,
49-
HttpServletResponse response) throws IOException {
45+
public ResponseEntity getDiscojuiceFeeds(@RequestParam(value = "callback", required = false) String callback) {
5046
// Download feeds
5147
String feedsContent = clarinDiscoJuiceFeedsUpdateScheduler.getFeedsContent();
5248
if (StringUtils.isBlank(feedsContent)) {
53-
response.sendError(HttpServletResponse.SC_NO_CONTENT);
54-
return null;
49+
// Return an empty but valid feed, not a 204: the JSONP client passes the body to
50+
// jQuery.merge() and an empty response throws on `undefined.length`.
51+
feedsContent = "[]";
5552
}
5653

5754
// If callback is not null wrap the feedsContent to the callback string.

dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsControllerIT.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import java.io.IOException;
1818
import java.io.InputStreamReader;
19+
import java.lang.reflect.Field;
1920
import java.net.URL;
2021
import java.net.URLConnection;
2122
import javax.net.ssl.HttpsURLConnection;
@@ -108,4 +109,30 @@ public void getDiscoFeeds() throws Exception {
108109

109110
configurationService.setProperty(configKey, origVal);
110111
}
112+
113+
@Test
114+
public void getDiscoFeedsWithoutContentReturnsEmptyFeed() throws Exception {
115+
// Simulate the default state where no feeds have been downloaded (discofeed disabled).
116+
Field feedsContentField = ClarinDiscoJuiceFeedsUpdateScheduler.class.getDeclaredField("feedsContent");
117+
feedsContentField.setAccessible(true);
118+
Object origFeedsContent = feedsContentField.get(null);
119+
feedsContentField.set(null, null);
120+
121+
try {
122+
// With a callback the JSONP wrapper must still be valid so the widget callback fires
123+
// with an (empty) array instead of `undefined`.
124+
getClient().perform(get("/api/discojuice/feeds?callback=dj_md_1"))
125+
.andExpect(status().isOk())
126+
.andExpect(content().contentType(APPLICATION_JAVASCRIPT_UTF8))
127+
.andExpect(content().string("dj_md_1([])"));
128+
129+
// Without a callback an empty JSON array is returned instead of a 204 No Content.
130+
getClient().perform(get("/api/discojuice/feeds"))
131+
.andExpect(status().isOk())
132+
.andExpect(content().contentType(APPLICATION_JAVASCRIPT_UTF8))
133+
.andExpect(content().string("[]"));
134+
} finally {
135+
feedsContentField.set(null, origFeedsContent);
136+
}
137+
}
111138
}

0 commit comments

Comments
 (0)