Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.result.ServletRedirectResult;

import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

Expand Down Expand Up @@ -129,6 +131,29 @@ public void execute(ActionInvocation invocation) throws Exception {
setLocation(tmpLocation.toString());
super.execute(invocation);
}

/**
* Jetty 12 (ee10) {@link HttpServletResponse#sendRedirect(String)} throws
* {@code IllegalArgumentException: Fragment} for any redirect location containing a URL fragment
* ({@code #anchor}). A fragment in the {@code Location} header is valid per RFC 7231 §7.1.2 and is
* honoured by browsers, so when the target carries an anchor we set the status + {@code Location}
* header directly — mirroring the superclass's own non-302 branch — instead of calling
* {@code sendRedirect}. Fragment-free locations keep the standard behaviour.
*/
@Override
protected void sendRedirect(HttpServletResponse response, String finalLocation) throws IOException {
if (null != finalLocation && finalLocation.indexOf('#') >= 0) {
response.setStatus(statusCode);
response.setHeader("Location", finalLocation);
try {
response.getWriter().write(finalLocation);
} finally {
response.getWriter().close();
}
return;
}
super.sendRedirect(response, finalLocation);
}

/**
* Sets the action name
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2015-Present Entando Inc. (http://www.entando.com) All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.agiletec.apsadmin.system.dispatcher;

import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import jakarta.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import org.junit.jupiter.api.Test;

/**
* Guards the Jetty 12 fix: a redirect location carrying a URL fragment must be emitted via the
* {@code Location} header (not {@code HttpServletResponse.sendRedirect}, which Jetty 12 rejects with
* {@code IllegalArgumentException: Fragment}), while fragment-free locations keep standard behaviour.
*/
class ServletActionRedirectResultWithAnchorTest {

private static final String ANCHOR_URL =
"/entando-de-app/do/Entity/CompositeAttribute/entryCompositeAttribute.action#fagiano_compositeTypesList";
private static final String PLAIN_URL =
"/entando-de-app/do/Entity/entryEntityType.action";

@Test
void locationWithAnchorIsSentViaHeaderNotSendRedirect() throws Exception {
ServletActionRedirectResultWithAnchor result = new ServletActionRedirectResultWithAnchor();
HttpServletResponse response = mock(HttpServletResponse.class);
when(response.getWriter()).thenReturn(mock(PrintWriter.class));

result.sendRedirect(response, ANCHOR_URL);

// 302 + Location header directly — never sendRedirect (which Jetty 12 would reject on the fragment)
verify(response).setStatus(HttpServletResponse.SC_FOUND);
verify(response).setHeader("Location", ANCHOR_URL);
verify(response, never()).sendRedirect(anyString());
}

@Test
void locationWithoutAnchorDelegatesToSendRedirect() throws Exception {
ServletActionRedirectResultWithAnchor result = new ServletActionRedirectResultWithAnchor();
HttpServletResponse response = mock(HttpServletResponse.class);

result.sendRedirect(response, PLAIN_URL);

verify(response).sendRedirect(PLAIN_URL);
verify(response, never()).setHeader(anyString(), anyString());
}
}
Loading