-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue #12505 - Server to Servlet Error Handling #12586
base: jetty-12.1.x
Are you sure you want to change the base?
Changes from 11 commits
37ab820
564e3ee
c9ee387
21f4f68
84892b7
119a930
bcf274d
135eb61
84d39e7
585aeed
db3f051
111c3fb
5257bba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,6 +42,7 @@ | |
import org.eclipse.jetty.http.HttpURI; | ||
import org.eclipse.jetty.http.pathmap.MatchedResource; | ||
import org.eclipse.jetty.io.WriterOutputStream; | ||
import org.eclipse.jetty.server.handler.ErrorHandler; | ||
import org.eclipse.jetty.util.Fields; | ||
import org.eclipse.jetty.util.IO; | ||
import org.eclipse.jetty.util.StringUtil; | ||
|
@@ -58,10 +59,10 @@ public class Dispatcher implements RequestDispatcher | |
* Dispatch include attribute names | ||
*/ | ||
public static final String __FORWARD_PREFIX = "jakarta.servlet.forward."; | ||
|
||
/** | ||
* Name of original request attribute | ||
*/ | ||
*/ | ||
public static final String __ORIGINAL_REQUEST = "org.eclipse.jetty.originalRequest"; | ||
|
||
public static final String JETTY_INCLUDE_HEADER_PREFIX = "org.eclipse.jetty.server.include."; | ||
|
@@ -316,15 +317,15 @@ public String getRequestURI() | |
@Override | ||
public StringBuffer getRequestURL() | ||
{ | ||
return _uri == null ? super.getRequestURL() : new StringBuffer(HttpURI.build(_uri).query(null).scheme(super.getScheme()).host(super.getServerName()).port(super.getServerPort()).asString()); | ||
return _uri == null ? super.getRequestURL() : new StringBuffer(HttpURI.build(_uri).query(null).scheme(super.getScheme()).host(super.getServerName()).port(super.getServerPort()).asString()); | ||
} | ||
|
||
@Override | ||
public Object getAttribute(String name) | ||
{ | ||
if (name == null) | ||
return null; | ||
|
||
//Servlet Spec 9.4.2 no forward attributes if a named dispatcher | ||
if (_named != null && name.startsWith(__FORWARD_PREFIX)) | ||
return null; | ||
|
@@ -356,7 +357,9 @@ public Object getAttribute(String name) | |
return originalRequest == null ? _httpServletRequest : originalRequest; | ||
} | ||
// Forward should hide include. | ||
case RequestDispatcher.INCLUDE_MAPPING, RequestDispatcher.INCLUDE_SERVLET_PATH, RequestDispatcher.INCLUDE_PATH_INFO, RequestDispatcher.INCLUDE_REQUEST_URI, RequestDispatcher.INCLUDE_CONTEXT_PATH, RequestDispatcher.INCLUDE_QUERY_STRING -> | ||
case RequestDispatcher.INCLUDE_MAPPING, RequestDispatcher.INCLUDE_SERVLET_PATH, | ||
RequestDispatcher.INCLUDE_PATH_INFO, RequestDispatcher.INCLUDE_REQUEST_URI, | ||
RequestDispatcher.INCLUDE_CONTEXT_PATH, RequestDispatcher.INCLUDE_QUERY_STRING -> | ||
{ | ||
return null; | ||
} | ||
|
@@ -380,11 +383,11 @@ public Object getAttribute(String name) | |
public Enumeration<String> getAttributeNames() | ||
{ | ||
ArrayList<String> names = new ArrayList<>(Collections.list(super.getAttributeNames())); | ||
|
||
//Servlet Spec 9.4.2 no forward attributes if a named dispatcher | ||
if (_named != null) | ||
return Collections.enumeration(names); | ||
|
||
names.add(RequestDispatcher.FORWARD_REQUEST_URI); | ||
names.add(RequestDispatcher.FORWARD_SERVLET_PATH); | ||
names.add(RequestDispatcher.FORWARD_PATH_INFO); | ||
|
@@ -416,7 +419,7 @@ public Object getAttribute(String name) | |
{ | ||
if (name == null) | ||
return null; | ||
|
||
//Servlet Spec 9.3.1 no include attributes if a named dispatcher | ||
if (_named != null && name.startsWith(__INCLUDE_PREFIX)) | ||
return null; | ||
|
@@ -440,7 +443,7 @@ public Enumeration<String> getAttributeNames() | |
ArrayList<String> names = new ArrayList<>(Collections.list(super.getAttributeNames())); | ||
if (_named != null) | ||
return Collections.enumeration(names); | ||
|
||
names.add(RequestDispatcher.INCLUDE_MAPPING); | ||
names.add(RequestDispatcher.INCLUDE_SERVLET_PATH); | ||
names.add(RequestDispatcher.INCLUDE_PATH_INFO); | ||
|
@@ -462,7 +465,7 @@ private static class IncludeResponse extends HttpServletResponseWrapper | |
ServletOutputStream _servletOutputStream; | ||
PrintWriter _printWriter; | ||
PrintWriter _mustFlush; | ||
|
||
public IncludeResponse(HttpServletResponse response) | ||
{ | ||
super(response); | ||
|
@@ -753,9 +756,12 @@ public Enumeration<String> getAttributeNames() | |
|
||
private class ErrorRequest extends ParameterRequestWrapper | ||
{ | ||
private final HttpServletRequest _httpServletRequest; | ||
|
||
public ErrorRequest(HttpServletRequest httpRequest) | ||
{ | ||
super(httpRequest); | ||
_httpServletRequest = httpRequest; | ||
} | ||
|
||
@Override | ||
|
@@ -797,6 +803,34 @@ public StringBuffer getRequestURL() | |
.port(getServerPort()) | ||
.asString()); | ||
} | ||
|
||
@Override | ||
public Object getAttribute(String name) | ||
{ | ||
return switch (name) | ||
{ | ||
case ERROR_REQUEST_URI -> _httpServletRequest.getRequestURI(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could call |
||
case ERROR_STATUS_CODE -> super.getAttribute(ErrorHandler.ERROR_STATUS); | ||
case ERROR_MESSAGE -> super.getAttribute(ErrorHandler.ERROR_MESSAGE); | ||
case ERROR_SERVLET_NAME -> super.getAttribute(ErrorHandler.ERROR_ORIGIN); | ||
case ERROR_EXCEPTION -> super.getAttribute(ErrorHandler.ERROR_EXCEPTION); | ||
case ERROR_EXCEPTION_TYPE -> | ||
{ | ||
Object err = super.getAttribute(ErrorHandler.ERROR_EXCEPTION); | ||
yield err == null ? null : err.getClass(); | ||
} | ||
default -> super.getAttribute(name); | ||
}; | ||
} | ||
|
||
@Override | ||
public Enumeration<String> getAttributeNames() | ||
{ | ||
// TODO add all names? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't you add all the names present in |
||
List<String> names = new ArrayList<>(List.of(ERROR_REQUEST_URI, ERROR_STATUS_CODE, ERROR_MESSAGE)); | ||
names.addAll(Collections.list(super.getAttributeNames())); | ||
return Collections.enumeration(names); | ||
} | ||
} | ||
|
||
@Override | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,6 +40,7 @@ | |
import static jakarta.servlet.RequestDispatcher.ERROR_REQUEST_URI; | ||
import static jakarta.servlet.RequestDispatcher.ERROR_SERVLET_NAME; | ||
import static jakarta.servlet.RequestDispatcher.ERROR_STATUS_CODE; | ||
import static org.eclipse.jetty.server.handler.ErrorHandler.ERROR_STATUS; | ||
|
||
/** | ||
* holder of the state of request-response cycle. | ||
|
@@ -423,6 +424,16 @@ public Action handling() | |
throw new IllegalStateException(getStatusStringLocked()); | ||
_initial = true; | ||
_state = State.HANDLING; | ||
if (_servletChannel.getResponse().getStatus() != 0) | ||
{ | ||
if (_servletChannel.getRequest().getAttribute(ERROR_STATUS) instanceof Integer errorCode) | ||
{ | ||
_servletChannel.getServletRequestState().sendError(errorCode, null); | ||
_requestState = RequestState.BLOCKING; | ||
_sendError = false; | ||
return Action.SEND_ERROR; | ||
} | ||
} | ||
return Action.DISPATCH; | ||
|
||
case WOKEN: | ||
|
@@ -1022,7 +1033,6 @@ else if (cause instanceof UnavailableException) | |
|
||
public void sendError(int code, String message) | ||
{ | ||
// This method is called by Response.sendError to organise for an error page to be generated when it is possible: | ||
// + The response is reset and temporarily closed. | ||
// + The details of the error are saved as request attributes | ||
// + The _sendError boolean is set to true so that an ERROR_DISPATCH action will be generated: | ||
|
@@ -1067,12 +1077,15 @@ public void sendError(int code, String message) | |
// Set Jetty Specific Attributes. | ||
request.setAttribute(ErrorHandler.ERROR_CONTEXT, servletContextRequest.getServletContext()); | ||
request.setAttribute(ErrorHandler.ERROR_MESSAGE, message); | ||
request.setAttribute(ErrorHandler.ERROR_STATUS, code); | ||
request.setAttribute(ERROR_STATUS, code); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why was |
||
request.setAttribute(ErrorHandler.ERROR_ORIGIN, servletContextRequest.getServletName()); | ||
|
||
_sendError = true; | ||
if (_event != null) | ||
{ | ||
Throwable cause = (Throwable)request.getAttribute(ERROR_EXCEPTION); | ||
if (cause == null) | ||
cause = (Throwable)request.getAttribute(ErrorHandler.ERROR_EXCEPTION); | ||
if (cause != null) | ||
_event.addThrowable(cause); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -73,6 +73,7 @@ | |
import org.eclipse.jetty.ee10.servlet.security.ConstraintAware; | ||
import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping; | ||
import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler; | ||
import org.eclipse.jetty.http.HttpStatus; | ||
import org.eclipse.jetty.http.HttpURI; | ||
import org.eclipse.jetty.http.pathmap.MatchedResource; | ||
import org.eclipse.jetty.io.IOResources; | ||
|
@@ -1147,7 +1148,6 @@ protected ContextRequest wrapRequest(Request request, Response response) | |
decodedPathInContext = URIUtil.decodePath(getContext().getPathInContext(request.getHttpURI().getCanonicalPath())); | ||
matchedResource = _servletHandler.getMatchedServlet(decodedPathInContext); | ||
|
||
|
||
if (matchedResource == null) | ||
return wrapNoServlet(request, response); | ||
ServletHandler.MappedServlet mappedServlet = matchedResource.getResource(); | ||
|
@@ -1196,7 +1196,14 @@ protected boolean handleByContextHandler(String pathInContext, ContextRequest re | |
boolean initialDispatch = request instanceof ServletContextRequest; | ||
if (!initialDispatch) | ||
return false; | ||
return super.handleByContextHandler(pathInContext, request, response, callback); | ||
|
||
if (isProtectedTarget(pathInContext)) | ||
{ | ||
// Do nothing here other than set the error status so that the ServletHandler will handle as if a sendError | ||
request.setAttribute(org.eclipse.jetty.server.handler.ErrorHandler.ERROR_STATUS, 404); | ||
response.setStatus(HttpStatus.NOT_FOUND_404); | ||
} | ||
return false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is now different to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The changes in ee11 required a change to the ErrorPageMapper API and implementation, that I do not want to do in EE10, so just doing the simplest solution here. In EE11, I have tried to clean up the ErrorPageMapper API somewhat... but I think more could be done (maybe a different PR?) |
||
} | ||
|
||
@Override | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is oddly aligned. I'm surprised checkstyle let it go through.