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

org.glassfish.grizzly.servlet.DispatchedHttpServletRequest Maven / Gradle / Ivy

There is a newer version: 4.1.0-M1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2008-2015 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 *
 *
 * This file incorporates work covered by the following copyright and
 * permission notice:
 *
 * Copyright 2004 The Apache Software Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.glassfish.grizzly.servlet;

import java.nio.charset.Charset;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.glassfish.grizzly.http.server.util.Enumerator;
import org.glassfish.grizzly.http.server.util.Globals;
import org.glassfish.grizzly.http.server.util.ParameterMap;
import org.glassfish.grizzly.http.util.Constants;
import org.glassfish.grizzly.http.util.DataChunk;
import org.glassfish.grizzly.http.util.Parameters;
import org.glassfish.grizzly.utils.Charsets;

/**
 * Wrapper around a javax.servlet.http.HttpServletRequest
 * that transforms an application request object (which might be the original
 * one passed to a servlet.
 *
 * @author Bongjae Chang
 */
public class DispatchedHttpServletRequest extends HttpServletRequestWrapper {

    // ------------------------------------------------------- Static Variables

    /**
     * The set of attribute names that are special for request dispatchers
     */
    private static final HashSet specials = new HashSet(15);

    static {
        specials.add(RequestDispatcher.INCLUDE_REQUEST_URI);
        specials.add(RequestDispatcher.INCLUDE_CONTEXT_PATH);
        specials.add(RequestDispatcher.INCLUDE_SERVLET_PATH);
        specials.add(RequestDispatcher.INCLUDE_PATH_INFO);
        specials.add(RequestDispatcher.INCLUDE_QUERY_STRING);
        specials.add(RequestDispatcher.FORWARD_REQUEST_URI);
        specials.add(RequestDispatcher.FORWARD_CONTEXT_PATH);
        specials.add(RequestDispatcher.FORWARD_SERVLET_PATH);
        specials.add(RequestDispatcher.FORWARD_PATH_INFO);
        specials.add(RequestDispatcher.FORWARD_QUERY_STRING);
        specials.add(AsyncContext.ASYNC_REQUEST_URI);
        specials.add(AsyncContext.ASYNC_CONTEXT_PATH);
        specials.add(AsyncContext.ASYNC_SERVLET_PATH);
        specials.add(AsyncContext.ASYNC_PATH_INFO);
        specials.add(AsyncContext.ASYNC_QUERY_STRING);
    }


    // ----------------------------------------------------------- Constructors

    /**
     * Construct a new wrapped request around the specified servlet request.
     *
     * @param request the servlet request being wrapped
     * @param dispatcherType the dispatcher type
     */
    public DispatchedHttpServletRequest(HttpServletRequest request,
            WebappContext context,
            boolean crossContext,
            DispatcherType dispatcherType) {
        super(request);
        this.context = context;
        this.crossContext = crossContext;
        this.dispatcherType = dispatcherType;

        setRequest(request);
    }
    
    
    // ----------------------------------------------------- Instance Variables

    /**
     * The context for this request.
     */
    protected WebappContext context = null;

    /**
     * The context path for this request.
     */
    protected String contextPath = null;
    
    /**
     * If this request is cross context, since this changes session access
     * behavior.
     */
    protected boolean crossContext = false;

    /**
     * The dispatcher type.
     */
    protected final DispatcherType dispatcherType;

    /**
     * Hash map used in the getParametersMap method.
     */
    private final ParameterMap parameterMap = new ParameterMap();
    private final Parameters mergedParameters = new Parameters();

    /**
     * Have the parameters for this request already been parsed?
     */
    private boolean parsedParams = false;
    
    /**
     * The path information for this request.
     */
    protected String pathInfo = null;

    /**
     * The query parameters for the current request.
     */
    private String queryParamString = null;

    /**
     * The query string for this request.
     */
    protected String queryString = null;

    /**
     * The current request dispatcher path.
     */
    protected Object requestDispatcherPath = null;

    /**
     * The request URI for this request.
     */
    protected String requestURI = null;

    /**
     * The servlet path for this request.
     */
    protected String servletPath = null;

    /**
     * Special attributes.
     */
    private HashMap specialAttributes = null;

    // ------------------------------------------------- ServletRequest Methods

    /**
     * Override the getAttribute() method of the wrapped request.
     *
     * @param name Name of the attribute to retrieve
     */
    @Override
    public Object getAttribute(String name) {

        if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) {
            if ( requestDispatcherPath != null ){
                return requestDispatcherPath.toString();
            } else {
                return null;   
            }
        }

        if (!isSpecial(name)) {
            return getRequest().getAttribute(name);
        } else {
            Object value = null;
            if (specialAttributes != null) {
                value = specialAttributes.get(name);
            }
            if (value == null && name.startsWith("javax.servlet.forward")) {
                /*
                 * If it's a forward special attribute, and null, delegate
                 * to the wrapped request. This will allow access to the
                 * forward special attributes from a request that was first
                 * forwarded and then included, or forwarded multiple times
                 * in a row.
                 * Notice that forward special attributes are set only on
                 * the wrapper that was created for the initial forward
                 * (i.e., the top-most wrapper for a request that was
                 * forwarded multiple times in a row, and never included,
                 * will not contain any specialAttributes!).
                 * This is different from an include, where the special
                 * include attributes are set on every include wrapper.
                 */
                value = getRequest().getAttribute(name);
            }
            return value;
        }

    }


    /**
     * Override the getAttributeNames() method of the wrapped
     * request.
     */
    @Override
    public Enumeration getAttributeNames() {
        return (new AttributeNamesEnumerator());
    }

    /**
     * Override the removeAttribute() method of the
     * wrapped request.
     *
     * @param name Name of the attribute to remove
     */
    @Override
    public void removeAttribute(String name) {

        if (isSpecial(name)) {
            if (specialAttributes != null) {
                specialAttributes.remove(name);
            }
        } else {
            getRequest().removeAttribute(name);
        }
    }


    /**
     * Override the setAttribute() method of the
     * wrapped request.
     *
     * @param name Name of the attribute to set
     * @param value Value of the attribute to set
     */
    @Override
    public void setAttribute(String name, Object value) {

        if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) {
            requestDispatcherPath = value;
            return;
        }

        if (isSpecial(name)) {
            if (specialAttributes != null) {
                specialAttributes.put(name, value);
            }
        } else {
            getRequest().setAttribute(name, value);
        }
    }
    

    /**
     * Return a RequestDispatcher that wraps the resource at the specified
     * path, which may be interpreted as relative to the current request path.
     *
     * @param path Path of the resource to be wrapped
     */
    @Override
    public RequestDispatcher getRequestDispatcher(String path) {

        if (context == null)
            return (null);

        // If the path is already context-relative, just pass it through
        if (path == null)
            return (null);
        else if (path.startsWith("/"))
            return (context.getRequestDispatcher(path));

        // Convert a request-relative path to a context-relative one
        String servletPath = 
            (String) getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH);
        if (servletPath == null)
            servletPath = getServletPath();

        // Add the path info, if there is any
        String pathInfo = getPathInfo();
        String requestPath = null;

        if (pathInfo == null) {
            requestPath = servletPath;
        } else {
            requestPath = servletPath + pathInfo;
        }

        int pos = requestPath.lastIndexOf('/');
        String relative = null;
        if (pos >= 0) {
            relative = requestPath.substring(0, pos + 1) + path;
        } else {
            relative = requestPath + path;
        }

        return (context.getRequestDispatcher(relative));

    }
    
    
    @Override
    public DispatcherType getDispatcherType() {
        return dispatcherType;
    }


    // --------------------------------------------- HttpServletRequest Methods


    /**
     * Override the getContextPath() method of the wrapped
     * request.
     */
    @Override
    public String getContextPath() {

        return (this.contextPath);

    }
    
    
    /**
     * Override the getParameter() method of the wrapped request.
     *
     * @param name Name of the requested parameter
     */
    @Override
    public String getParameter(String name) {

        if (!parsedParams) {
            parseParameters();
        }
        if (System.getSecurityManager() != null) {
            return AccessController.doPrivileged(
                    new GetParameterPrivilegedAction(name));
        } else {
            return mergedParameters.getParameter(name);
        }
    }


    /**
     * Override the getParameterMap() method of the
     * wrapped request.
     */
    @Override
    public Map getParameterMap() {
        if (!parsedParams) {
            parseParameters();
        }
        if (System.getSecurityManager() != null) {
            return AccessController.doPrivileged(
                    new GetParameterMapPrivilegedAction());
        } else {
            return getParameterMapInternal();
        }
    }


    /**
     * Override the getParameterNames() method of the
     * wrapped request.
     */
    @Override
    public Enumeration getParameterNames() {
        if (!parsedParams) {
            parseParameters();
        }
        if (System.getSecurityManager() != null) {
            return new Enumerator(AccessController.doPrivileged(
                    new GetParameterNamesPrivilegedAction()));
        } else {
            return new Enumerator(mergedParameters.getParameterNames());
        }
    }


    /**
     * Override the getParameterValues() method of the
     * wrapped request.
     *
     * @param name Name of the requested parameter
     */
    @Override
    public String[] getParameterValues(String name) {
        if (!parsedParams) {
            parseParameters();
        }
        String[] ret;
        /*
         * Clone the returned array only if there is a security manager
         * in place, so that performance won't suffer in the nonsecure case
         */
        if (System.getSecurityManager() != null) {
            ret = AccessController.doPrivileged(
                    new GetParameterValuePrivilegedAction(name));
            if (ret != null) {
                ret = ret.clone();
            }
        } else {
            ret = mergedParameters.getParameterValues(name);
        }
        return ret;
    }

    private ParameterMap getParameterMapInternal() {
        if (parameterMap.isLocked()) {
            return parameterMap;
        }
        for (final String name : mergedParameters.getParameterNames()) {
            final String[] values = mergedParameters.getParameterValues(name);
            parameterMap.put(name, values);
        }
        parameterMap.setLocked(true);
        return parameterMap;
    }

    /**
     * Parses the parameters of this request.
     * 

* If parameters are present in both the query string and the request * content, they are merged. */ @SuppressWarnings( "unchecked") private void parseParameters() { if (parsedParams) { return; } final String enc = getCharacterEncoding(); Charset charset; if (enc != null) { try { charset = Charsets.lookupCharset(enc); } catch (Exception e) { charset = Constants.DEFAULT_HTTP_CHARSET; } } else { charset = Constants.DEFAULT_HTTP_CHARSET; } mergedParameters.setEncoding(charset); mergedParameters.setQueryStringEncoding(charset); DataChunk queryDC = DataChunk.newInstance(); queryDC.setString(queryParamString); mergedParameters.setQuery(queryDC); mergedParameters.handleQueryParameters(); Map paramMap = getRequest().getParameterMap(); for (final Map.Entry entry : paramMap.entrySet()) { mergedParameters.addParameterValues(entry.getKey(), entry.getValue()); } parsedParams = true; } /** * Override the getPathInfo() method of the wrapped request. */ @Override public String getPathInfo() { return (this.pathInfo); } /** * Override the getQueryString() method of the wrapped * request. */ @Override public String getQueryString() { return (this.queryString); } /** * Override the getRequestURI() method of the wrapped * request. */ @Override public String getRequestURI() { return (this.requestURI); } /** * Override the getRequestURL() method of the wrapped * request. */ @Override public StringBuffer getRequestURL() { StringBuffer url = new StringBuffer(); String scheme = getScheme(); int port = getServerPort(); if (port < 0) port = 80; // Work around java.net.URL bug url.append(scheme); url.append("://"); url.append(getServerName()); if ((scheme.equals("http") && (port != 80)) || (scheme.equals("https") && (port != 443))) { url.append(':'); url.append(port); } url.append(getRequestURI()); return (url); } /** * Override the getServletPath() method of the wrapped * request. */ @Override public String getServletPath() { return (this.servletPath); } // -------------------------------------------------------- Package Methods /** * Perform a shallow copy of the specified Map, and return the result. * * @param orig Origin Map to be copied */ void copyMap(Map orig, Map dest) { if (orig == null) return; //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized (orig) { for (Map.Entry entry : orig.entrySet()) { dest.put(entry.getKey(), entry.getValue()); } } } /** * Set the context path for this request. * * @param contextPath The new context path */ void setContextPath(String contextPath) { this.contextPath = contextPath; } /** * Set the path information for this request. * * @param pathInfo The new path info */ void setPathInfo(String pathInfo) { this.pathInfo = pathInfo; } /** * Set the query string for this request. * * @param queryString The new query string */ void setQueryString(String queryString) { this.queryString = queryString; } /** * Set the request that we are wrapping. * * @param request The new wrapped request */ void setRequest(HttpServletRequest request) { super.setRequest(request); // Initialize the attributes for this request requestDispatcherPath = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR); // Initialize the path elements for this request contextPath = request.getContextPath(); pathInfo = request.getPathInfo(); queryString = request.getQueryString(); requestURI = request.getRequestURI(); servletPath = request.getServletPath(); } /** * Set the request URI for this request. * * @param requestURI The new request URI */ void setRequestURI(String requestURI) { this.requestURI = requestURI; } /** * Set the servlet path for this request. * * @param servletPath The new servlet path */ void setServletPath(String servletPath) { this.servletPath = servletPath; } /** * Save query parameters for this request. * * @param queryString The query string containing parameters for this * request */ void setQueryParams(String queryString) { this.queryParamString = queryString; } // ------------------------------------------------------ Protected Methods /** * Is this attribute name one of the special ones that is added only for * included servlets? * * @param name Attribute name to be tested */ protected boolean isSpecial(String name) { return specials.contains(name); } /** * Initializes the special attributes of this request wrapper. * * @param requestUri The request URI * @param contextPath The context path * @param servletPath The servlet path * @param pathInfo The path info * @param queryString The query string */ void initSpecialAttributes(String requestUri, String contextPath, String servletPath, String pathInfo, String queryString) { specialAttributes = new HashMap(5); switch (dispatcherType) { case INCLUDE: specialAttributes.put(RequestDispatcher.INCLUDE_REQUEST_URI, requestUri); specialAttributes.put(RequestDispatcher.INCLUDE_CONTEXT_PATH, contextPath); specialAttributes.put(RequestDispatcher.INCLUDE_SERVLET_PATH, servletPath); specialAttributes.put(RequestDispatcher.INCLUDE_PATH_INFO, pathInfo); specialAttributes.put(RequestDispatcher.INCLUDE_QUERY_STRING, queryString); break; case FORWARD: case ERROR: specialAttributes.put(RequestDispatcher.FORWARD_REQUEST_URI, requestUri); specialAttributes.put(RequestDispatcher.FORWARD_CONTEXT_PATH, contextPath); specialAttributes.put(RequestDispatcher.FORWARD_SERVLET_PATH, servletPath); specialAttributes.put(RequestDispatcher.FORWARD_PATH_INFO, pathInfo); specialAttributes.put(RequestDispatcher.FORWARD_QUERY_STRING, queryString); break; case ASYNC: specialAttributes.put(AsyncContext.ASYNC_REQUEST_URI, requestUri); specialAttributes.put(AsyncContext.ASYNC_CONTEXT_PATH, contextPath); specialAttributes.put(AsyncContext.ASYNC_SERVLET_PATH, servletPath); specialAttributes.put(AsyncContext.ASYNC_PATH_INFO, pathInfo); specialAttributes.put(AsyncContext.ASYNC_QUERY_STRING, queryString); break; default: // REQUEST break; } } /** * Merge the two sets of parameter values into a single String array. * * @param values1 First set of values * @param values2 Second set of values */ protected String[] mergeValues(Object values1, Object values2) { ArrayList results = new ArrayList(); if (values1 == null) ; else if (values1 instanceof String) results.add((String)values1); else if (values1 instanceof String[]) { String values[] = (String[]) values1; Collections.addAll(results, values); } else results.add(values1.toString()); if (values2 == null) ; else if (values2 instanceof String) results.add((String)values2); else if (values2 instanceof String[]) { String values[] = (String[]) values2; Collections.addAll(results, values); } else results.add(values2.toString()); String values[] = new String[results.size()]; return results.toArray(values); } public void recycle() { // parameterMap.setLocked( false ); // parameterMap.clear(); } // ----------------------------------- AttributeNamesEnumerator Inner Class /** * Utility class used to expose the special attributes as being available * as request attributes. */ private final class AttributeNamesEnumerator implements Enumeration { Enumeration parentEnumeration = null; String next = null; private Iterator specialNames = null; @SuppressWarnings( "unchecked" ) public AttributeNamesEnumerator() { parentEnumeration = getRequest().getAttributeNames(); if (specialAttributes != null) { specialNames = specialAttributes.keySet().iterator(); } } @Override public boolean hasMoreElements() { return (specialNames != null && specialNames.hasNext()) || (next != null) || ((next = findNext()) != null); } @Override public String nextElement() { if (specialNames != null && specialNames.hasNext()) { return specialNames.next(); } String result = next; if (next != null) { next = findNext(); } else { throw new NoSuchElementException(); } return result; } protected String findNext() { String result = null; while ((result == null) && (parentEnumeration.hasMoreElements())) { String current = parentEnumeration.nextElement(); if (!isSpecial(current) || (!dispatcherType.equals(DispatcherType.FORWARD) && current.startsWith("javax.servlet.forward") && getAttribute(current) != null)) { result = current; } } return result; } } public HttpServletRequestImpl getRequestFacade() { if (getRequest() instanceof HttpServletRequestImpl) { return (HttpServletRequestImpl) getRequest(); } else { return ((DispatchedHttpServletRequest)getRequest()).getRequestFacade(); } } private final class GetParameterPrivilegedAction implements PrivilegedAction { public final String name; public GetParameterPrivilegedAction( String name ) { this.name = name; } @Override public String run() { return mergedParameters.getParameter( name ); } } private final class GetParameterNamesPrivilegedAction implements PrivilegedAction> { @Override public Set run() { return mergedParameters.getParameterNames(); } } private final class GetParameterValuePrivilegedAction implements PrivilegedAction { public final String name; public GetParameterValuePrivilegedAction( String name ) { this.name = name; } @Override public String[] run() { return mergedParameters.getParameterValues( name ); } } private final class GetParameterMapPrivilegedAction implements PrivilegedAction { @Override public ParameterMap run() { return getParameterMapInternal(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy