org.eclipse.jetty.ee8.nested.CrossContextDispatcher Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jetty-ee8-nested Show documentation
Show all versions of jetty-ee8-nested Show documentation
The jetty core handler adapted to legacy ee8 handler.
The newest version!
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.ee8.nested;
import java.io.Closeable;
import java.io.IOException;
import java.util.Objects;
import java.util.Set;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.server.FormFields;
import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.util.Blocker;
import org.eclipse.jetty.util.IO;
class CrossContextDispatcher implements RequestDispatcher {
public static final String ORIGINAL_URI = "org.eclipse.jetty.dispatch.originalURI";
public static final String ORIGINAL_QUERY_STRING = "org.eclipse.jetty.dispatch.originalQueryString";
public static final String ORIGINAL_SERVLET_MAPPING = "org.eclipse.jetty.dispatch.originalServletMapping";
public static final String ORIGINAL_CONTEXT_PATH = "org.eclipse.jetty.dispatch.originalContextPath";
//EE8EE9-TRANSLATE
private static final String FOREIGN_SERVLET_PACKAGE = "jakarta.servlet.";
public static final Set ATTRIBUTES = Set.of(RequestDispatcher.FORWARD_REQUEST_URI, RequestDispatcher.FORWARD_MAPPING, RequestDispatcher.FORWARD_CONTEXT_PATH, RequestDispatcher.FORWARD_SERVLET_PATH, RequestDispatcher.FORWARD_QUERY_STRING, RequestDispatcher.FORWARD_PATH_INFO, RequestDispatcher.INCLUDE_REQUEST_URI, RequestDispatcher.INCLUDE_MAPPING, RequestDispatcher.INCLUDE_CONTEXT_PATH, RequestDispatcher.INCLUDE_SERVLET_PATH, RequestDispatcher.INCLUDE_QUERY_STRING, RequestDispatcher.INCLUDE_PATH_INFO, // TODO MULTIPART_CONFIG_ELEMENT,
org.eclipse.jetty.server.handler.ContextHandler.CROSS_CONTEXT_ATTRIBUTE, ORIGINAL_URI, ORIGINAL_QUERY_STRING, ORIGINAL_SERVLET_MAPPING, ORIGINAL_CONTEXT_PATH, FormFields.class.getName());
private final CrossContextServletContext _targetContext;
private final HttpURI _uri;
private final String _decodedPathInContext;
private class IncludeRequest extends ServletCoreRequest {
private Request _baseRequest;
public IncludeRequest(ContextHandler.CoreContextRequest coreContextRequest, Request request, HttpServletRequest httpServletRequest) {
super(coreContextRequest, httpServletRequest, new Attributes.Synthetic(new ServletAttributes(httpServletRequest)) {
@Override
public Object getAttribute(String name) {
//handle cross-environment dispatch from ee8
if (name.startsWith(FOREIGN_SERVLET_PACKAGE))
name = "javax.servlet." + name.substring(FOREIGN_SERVLET_PACKAGE.length());
return super.getAttribute(name);
}
@Override
protected Object getSyntheticAttribute(String name) {
if (name == null)
return null;
//Special include attributes refer to the target context and path
return switch(name) {
case RequestDispatcher.INCLUDE_MAPPING ->
null;
case RequestDispatcher.INCLUDE_SERVLET_PATH ->
null;
case RequestDispatcher.INCLUDE_PATH_INFO ->
_decodedPathInContext;
case RequestDispatcher.INCLUDE_REQUEST_URI ->
(_uri == null) ? null : _uri.getPath();
case RequestDispatcher.INCLUDE_CONTEXT_PATH ->
_targetContext.getContextPath();
case RequestDispatcher.INCLUDE_QUERY_STRING ->
(_uri == null) ? null : _uri.getQuery();
case org.eclipse.jetty.server.handler.ContextHandler.CROSS_CONTEXT_ATTRIBUTE ->
DispatcherType.INCLUDE.toString();
case ORIGINAL_URI ->
httpServletRequest.getRequestURI();
case ORIGINAL_QUERY_STRING ->
httpServletRequest.getQueryString();
case ORIGINAL_SERVLET_MAPPING ->
httpServletRequest.getHttpServletMapping();
case ORIGINAL_CONTEXT_PATH ->
httpServletRequest.getContextPath();
default ->
httpServletRequest.getAttribute(name);
};
}
@Override
protected Set getSyntheticNameSet() {
return ATTRIBUTES;
}
@Override
public Object setAttribute(String name, Object attribute) {
if (name == null)
return null;
//handle cross-environment dispatch from ee8
if (name.startsWith(FOREIGN_SERVLET_PACKAGE))
name = "javax.servlet." + name.substring(FOREIGN_SERVLET_PACKAGE.length());
return super.setAttribute(name, attribute);
}
});
_baseRequest = request;
}
@Override
public HttpURI getHttpURI() {
//return the uri of the dispatch target
return _uri;
}
@Override
public Object getAttribute(String name) {
if (MultiPart.Parser.class.getName().equals(name))
return _baseRequest.getAttribute(name);
return super.getAttribute(name);
}
}
private class IncludeResponse extends ServletCoreResponse {
public IncludeResponse(ServletCoreRequest servletCoreRequest, HttpServletResponse httpServletResponse, Response baseResponse, org.eclipse.jetty.server.Response coreResponse) {
super(servletCoreRequest, httpServletResponse, baseResponse, coreResponse, true);
}
}
private class ForwardRequest extends ServletCoreRequest {
private Request _baseRequest;
private HttpURI _fullyQualifiedURI;
public ForwardRequest(ContextHandler.CoreContextRequest coreContextRequest, Request request, HttpServletRequest httpServletRequest) {
super(coreContextRequest, httpServletRequest, new Attributes.Synthetic(new ServletAttributes(httpServletRequest)) {
@Override
protected Object getSyntheticAttribute(String name) {
if (name == null)
return null;
//handle cross-environment dispatch from ee8
if (name.startsWith(FOREIGN_SERVLET_PACKAGE))
name = "javax.servlet." + name.substring(FOREIGN_SERVLET_PACKAGE.length());
return switch(name) {
case RequestDispatcher.FORWARD_REQUEST_URI ->
httpServletRequest.getRequestURI();
case RequestDispatcher.FORWARD_SERVLET_PATH ->
httpServletRequest.getServletPath();
case RequestDispatcher.FORWARD_PATH_INFO ->
httpServletRequest.getPathInfo();
case RequestDispatcher.FORWARD_CONTEXT_PATH ->
httpServletRequest.getContextPath();
case RequestDispatcher.FORWARD_MAPPING ->
httpServletRequest.getHttpServletMapping();
case RequestDispatcher.FORWARD_QUERY_STRING ->
httpServletRequest.getQueryString();
case RequestDispatcher.INCLUDE_MAPPING ->
REMOVED;
case RequestDispatcher.INCLUDE_REQUEST_URI ->
REMOVED;
case RequestDispatcher.INCLUDE_CONTEXT_PATH ->
REMOVED;
case RequestDispatcher.INCLUDE_QUERY_STRING ->
REMOVED;
case RequestDispatcher.INCLUDE_SERVLET_PATH ->
REMOVED;
case RequestDispatcher.INCLUDE_PATH_INFO ->
REMOVED;
// TODO case ServletContextRequest.MULTIPART_CONFIG_ELEMENT -> httpServletRequest.getAttribute(ServletMultiPartFormData.class.getName());
case org.eclipse.jetty.server.handler.ContextHandler.CROSS_CONTEXT_ATTRIBUTE ->
DispatcherType.FORWARD.toString();
default ->
{
if (FormFields.class.getName().equals(name)) {
Request baseRequest = Objects.requireNonNull(Request.getBaseRequest(httpServletRequest));
yield baseRequest.peekParameters();
}
yield null;
}
};
}
@Override
protected Set getSyntheticNameSet() {
return ATTRIBUTES;
}
});
_baseRequest = request;
_fullyQualifiedURI = HttpURI.build(request.getRootURL().toString()).pathQuery(_uri.getPathQuery()).asImmutable();
}
@Override
public Object getAttribute(String name) {
if (MultiPart.Parser.class.getName().equals(name))
return _baseRequest.getAttribute(name);
return super.getAttribute(name);
}
@Override
public HttpURI getHttpURI() {
return _fullyQualifiedURI;
}
}
CrossContextDispatcher(CrossContextServletContext targetContext, HttpURI uri, String decodedPathInContext) {
_targetContext = targetContext;
_uri = uri;
_decodedPathInContext = decodedPathInContext;
}
@Override
public void forward(ServletRequest servletRequest, ServletResponse response) throws ServletException, IOException {
HttpServletRequest httpServletRequest = (servletRequest instanceof HttpServletRequest) ? ((HttpServletRequest) servletRequest) : new ServletRequestHttpWrapper(servletRequest);
HttpServletResponse httpServletResponse = (response instanceof HttpServletResponse) ? (HttpServletResponse) response : new ServletResponseHttpWrapper(response);
Request baseRequest = Objects.requireNonNull(Request.getBaseRequest(servletRequest));
Response baseResponse = baseRequest.getResponse();
ContextHandler.CoreContextRequest coreContextRequest = baseRequest.getCoreRequest();
org.eclipse.jetty.server.Response coreResponse = coreContextRequest.getHttpChannel().getCoreResponse();
baseResponse.resetForForward();
//if forwarding to the same environment we must mutate this request for Object wrapper identity
if (_targetContext.getTargetContext().getContextHandler() instanceof ContextHandler.CoreContextHandler coreContextHandler) {
new Dispatcher(coreContextHandler.getContextHandler(), _uri, _decodedPathInContext).forward(httpServletRequest, httpServletResponse, DispatcherType.FORWARD);
return;
}
ForwardRequest forwardRequest = new ForwardRequest(coreContextRequest, baseRequest, httpServletRequest);
ServletCoreResponse servletCoreResponse = new ServletCoreResponse(forwardRequest, httpServletResponse, baseResponse, coreResponse, false);
try (Blocker.Callback callback = Blocker.callback()) {
_targetContext.getTargetContext().getContextHandler().handle(forwardRequest, servletCoreResponse, callback);
callback.block();
} catch (Exception e) {
throw new ServletException(e);
}
// If we are not async and not closed already, then close via the possibly wrapped response.
if (!baseRequest.isAsyncStarted() && !servletCoreResponse.hasLastWrite()) {
Closeable closeable;
try {
closeable = response.getOutputStream();
} catch (IllegalStateException e) {
closeable = response.getWriter();
}
IO.close(closeable);
}
}
@Override
public void include(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
HttpServletRequest httpServletRequest = (servletRequest instanceof HttpServletRequest) ? ((HttpServletRequest) servletRequest) : new ServletRequestHttpWrapper(servletRequest);
HttpServletResponse httpServletResponse = (servletResponse instanceof HttpServletResponse) ? (HttpServletResponse) servletResponse : new ServletResponseHttpWrapper(servletResponse);
Request baseRequest = Objects.requireNonNull(Request.getBaseRequest(servletRequest));
Response baseResponse = baseRequest.getResponse();
ContextHandler.CoreContextRequest coreContextRequest = baseRequest.getCoreRequest();
org.eclipse.jetty.server.Response coreResponse = coreContextRequest.getHttpChannel().getCoreResponse();
//if including to the same environment we must mutate this request for Object wrapper identity
if (_targetContext.getTargetContext().getContextHandler() instanceof ContextHandler.CoreContextHandler coreContextHandler) {
new Dispatcher(coreContextHandler.getContextHandler(), _uri, _decodedPathInContext).include(httpServletRequest, httpServletResponse);
return;
}
IncludeRequest includeRequest = new IncludeRequest(coreContextRequest, baseRequest, httpServletRequest);
IncludeResponse includeResponse = new IncludeResponse(includeRequest, httpServletResponse, baseResponse, coreResponse);
try (Blocker.Callback callback = Blocker.callback()) {
_targetContext.getTargetContext().getContextHandler().handle(includeRequest, includeResponse, callback);
callback.block();
} catch (Exception e) {
throw new ServletException(e);
}
}
}