All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.ee8.nested.CrossContextDispatcher Maven / Gradle / Ivy

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);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy