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

javax.faces.webapp.FacesServlet Maven / Gradle / Ivy

The newest version!
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 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.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.
 */

package javax.faces.webapp;


import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.Set;
import java.util.HashSet;
import java.util.List;

import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.application.ResourceHandler;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.UnavailableException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * 

FacesServlet is a * servlet that manages the request processing lifecycle for web * applications that are utilizing JavaServer Faces to construct the * user interface.

* *
* *

If the application is running in a Servlet 3.0 (and beyond) * container, the runtime must provide an implementation of the {@link * javax.servlet.ServletContainerInitializer} interface that declares * the following classes in its {@link * javax.servlet.annotation.HandlesTypes} annotation.

*
    *
  • {@link javax.faces.annotation.FacesConfig}
  • *
  • {@link javax.faces.application.ResourceDependencies}
  • *
  • {@link javax.faces.application.ResourceDependency}
  • *
  • javax.faces.bean.ManagedBean
  • *
  • {@link javax.faces.component.FacesComponent}
  • *
  • {@link javax.faces.component.UIComponent}
  • *
  • {@link javax.faces.convert.Converter}
  • *
  • {@link javax.faces.convert.FacesConverter}
  • *
  • {@link javax.faces.event.ListenerFor}
  • *
  • {@link javax.faces.event.ListenersFor}
  • *
  • {@link javax.faces.render.FacesBehaviorRenderer}
  • *
  • {@link javax.faces.render.Renderer}
  • *
  • {@link javax.faces.validator.FacesValidator}
  • *
  • {@link javax.faces.validator.Validator}
  • *
*

This servlet must automatically be mapped if it is * not explicitly mapped in web.xml or * web-fragment.xml and one or more of the following * conditions are true.

*
    *
  • A faces-config.xml file is found in * WEB-INF

  • *
  • A faces-config.xml file is found in the * META-INF directory of a jar in the application's * classpath.

  • *
  • A filename ending in .faces-config.xml is * found in the META-INF directory of a jar in the * application's classpath.

  • *
  • The javax.faces.CONFIG_FILES context param * is declared in web.xml or * web-fragment.xml.

  • *
  • The Set of classes passed to the * onStartup() method of the * ServletContainerInitializer implementation is not * empty.

  • *
*

If the runtime determines that the servlet must be automatically * mapped, it must be mapped to the following * <url-pattern> entries.

*
    *
  • /faces/*
  • *
  • *.jsf
  • *
  • *.faces
  • *
  • *.xhtml
  • *
*
* *

Note that the automatic mapping to {@code *.xhtml} * can be disabled with the context param {@link #DISABLE_FACESSERVLET_TO_XHTML_PARAM_NAME}.

*
* *

This class must be annotated with {@code javax.servlet.annotation.MultipartConfig}. * This causes the Servlet container in which the JSF implementation is running * to correctly handle multipart form data.

*

Some security considerations relating to this class

*

The topic of web application security is a cross-cutting concern * and every aspect of the specification address it. However, as with * any framework, the application developer needs to pay careful * attention to security. Please consider these topics among the rest * of the security concerns for the application. This is by no means a * complete list of security concerns, and is no substitute for a * thorough application level security review.

* *
*

Prefix mappings and the FacesServlet

*

If the FacesServlet is mapped using a prefix * <url-pattern>, such as * <url-pattern>/faces/*</url-pattern>, * something must be done to prevent access to the view source without * its first being processed by the FacesServlet. One * common approach is to apply a <security-constraint> to all * facelet files and flow definition files. Please see the * Deployment Descriptor chapter of the Java Servlet * Specification for more information the use of * <security-constraint>.

*

Allowable HTTP Methods

*

The JSF specification only requires the use of the GET and POST * http methods. If your web application does not require any other * http methods, such as PUT and DELETE, please consider restricting the * allowable http methods using the <http-method> and * <http-method-omission> elements. Please see the * Security of the Java Servlet Specification for more * information the use of these elements.

*
* *
*/ @MultipartConfig public final class FacesServlet implements Servlet { /* * A white space separated list of case sensitive HTTP method names * that are allowed to be processed by this servlet. * means allow all */ private static final String ALLOWED_HTTP_METHODS_ATTR = "com.sun.faces.allowedHttpMethods"; // Http method names must be upper case. http://www.w3.org/Protocols/HTTP/NoteMethodCS.html // List of valid methods in Http 1.1 http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9 private enum HttpMethod { OPTIONS("OPTIONS"), GET("GET"), HEAD("HEAD"), POST("POST"), PUT("PUT"), DELETE("DELETE"), TRACE("TRACE"), CONNECT("CONNECT"); private String name; HttpMethod(String name) { this.name = name; } @Override public String toString() { return name; } } private Set allowedUnknownHttpMethods; private Set allowedKnownHttpMethods; final private Set defaultAllowedHttpMethods = EnumSet.range(HttpMethod.OPTIONS, HttpMethod.CONNECT); private Set allHttpMethods; private boolean allowAllMethods; /** *

Context initialization parameter name for a comma delimited list * of context-relative resource paths (in addition to * /WEB-INF/faces-config.xml which is loaded automatically * if it exists) containing JavaServer Faces configuration information.

*/ public static final String CONFIG_FILES_ATTR = "javax.faces.CONFIG_FILES"; /** *

Context initialization parameter name for the lifecycle identifier * of the {@link Lifecycle} instance to be utilized.

*/ public static final String LIFECYCLE_ID_ATTR = "javax.faces.LIFECYCLE_ID"; /** *

The ServletContext init * parameter consulted by the runtime to tell if the automatic mapping * of the {@code FacesServlet} to the extension {@code *.xhtml} * should be disabled. The implementation must disable this automatic * mapping if and only if the value of this parameter is equal, ignoring * case, to {@code true}.

* *

If this parameter is not specified, this automatic mapping is enabled * as specified above.

*/ public static final String DISABLE_FACESSERVLET_TO_XHTML_PARAM_NAME = "javax.faces.DISABLE_FACESSERVLET_TO_XHTML"; /** * The Logger for this class. */ private static final Logger LOGGER = Logger.getLogger("javax.faces.webapp", "javax.faces.LogStrings"); /** *

Factory for {@link FacesContext} instances.

*/ private FacesContextFactory facesContextFactory = null; /** *

The {@link Lifecycle} instance to use for request processing.

*/ private Lifecycle lifecycle = null; /** *

The ServletConfig instance for this servlet.

*/ private ServletConfig servletConfig = null; /** * From GLASSFISH-15632. If true, the FacesContext instance * left over from startup time has been released. */ private boolean initFacesContextReleased = false; /** *

Release all resources acquired at startup time.

*/ @Override public void destroy() { facesContextFactory = null; lifecycle = null; servletConfig = null; uninitHttpMethodValidityVerification(); } /** *

Return the ServletConfig instance for this servlet.

*/ @Override public ServletConfig getServletConfig() { return (this.servletConfig); } /** *

Return information about this Servlet.

*/ @Override public String getServletInfo() { return (this.getClass().getName()); } /** *

Acquire the factory instances we will require.

* * @throws ServletException if, for any reason, the startup of * this Faces application failed. This includes errors in the * config file that is parsed before or during the processing of * this init() method. */ @Override public void init(ServletConfig servletConfig) throws ServletException { // Save our ServletConfig instance this.servletConfig = servletConfig; // Acquire our FacesContextFactory instance try { facesContextFactory = (FacesContextFactory) FactoryFinder.getFactory (FactoryFinder.FACES_CONTEXT_FACTORY); } catch (FacesException e) { ResourceBundle rb = LOGGER.getResourceBundle(); String msg = rb.getString("severe.webapp.facesservlet.init_failed"); Throwable rootCause = (e.getCause() != null) ? e.getCause() : e; LOGGER.log(Level.SEVERE, msg, rootCause); throw new UnavailableException(msg); } // Acquire our Lifecycle instance try { LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY); String lifecycleId ; // First look in the servlet init-param set if (null == (lifecycleId = servletConfig.getInitParameter(LIFECYCLE_ID_ATTR))) { // If not found, look in the context-param set lifecycleId = servletConfig.getServletContext().getInitParameter (LIFECYCLE_ID_ATTR); } if (lifecycleId == null) { lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE; } lifecycle = lifecycleFactory.getLifecycle(lifecycleId); initHttpMethodValidityVerification(); } catch (FacesException e) { Throwable rootCause = e.getCause(); if (rootCause == null) { throw e; } else { throw new ServletException(e.getMessage(), rootCause); } } } private void initHttpMethodValidityVerification() { assert (null == allowedUnknownHttpMethods); assert (null != defaultAllowedHttpMethods); assert (null == allHttpMethods); allHttpMethods = EnumSet.allOf(HttpMethod.class); // Configure our permitted HTTP methods allowedUnknownHttpMethods = Collections.emptySet(); allowedKnownHttpMethods = defaultAllowedHttpMethods; String[] methods; String allowedHttpMethodsString = servletConfig.getServletContext().getInitParameter(ALLOWED_HTTP_METHODS_ATTR); if (null != allowedHttpMethodsString) { methods = allowedHttpMethodsString.split("\\s+"); assert (null != methods); // assuming split always returns a non-null array result allowedUnknownHttpMethods = new HashSet(methods.length); List allowedKnownHttpMethodsStringList = new ArrayList<>(); // validate input against allHttpMethods data structure for (String cur : methods) { if (cur.equals("*")) { allowAllMethods = true; allowedUnknownHttpMethods = Collections.emptySet(); return; } boolean isKnownHttpMethod; try { HttpMethod.valueOf(cur); isKnownHttpMethod = true; } catch (IllegalArgumentException e) { isKnownHttpMethod = false; } if (!isKnownHttpMethod) { if (LOGGER.isLoggable(Level.WARNING)) { HttpMethod [] values = HttpMethod.values(); Object [] arg = new Object[values.length + 1]; arg[0] = cur; System.arraycopy(values, HttpMethod.OPTIONS.ordinal(), arg, 1, values.length); LOGGER.log(Level.WARNING, "warning.webapp.facesservlet.init_invalid_http_method", arg); } // prevent duplicates if (!allowedUnknownHttpMethods.contains(cur)) { allowedUnknownHttpMethods.add(cur); } } else { // prevent duplicates if (!allowedKnownHttpMethodsStringList.contains(cur)) { allowedKnownHttpMethodsStringList.add(cur); } } } // Optimally initialize allowedKnownHttpMethods if (5 == allowedKnownHttpMethodsStringList.size()) { allowedKnownHttpMethods = EnumSet.of( HttpMethod.valueOf(allowedKnownHttpMethodsStringList.get(0)), HttpMethod.valueOf(allowedKnownHttpMethodsStringList.get(1)), HttpMethod.valueOf(allowedKnownHttpMethodsStringList.get(2)), HttpMethod.valueOf(allowedKnownHttpMethodsStringList.get(3)), HttpMethod.valueOf(allowedKnownHttpMethodsStringList.get(4)) ); } else if (4 == allowedKnownHttpMethodsStringList.size()) { allowedKnownHttpMethods = EnumSet.of( HttpMethod.valueOf(allowedKnownHttpMethodsStringList.get(0)), HttpMethod.valueOf(allowedKnownHttpMethodsStringList.get(1)), HttpMethod.valueOf(allowedKnownHttpMethodsStringList.get(2)), HttpMethod.valueOf(allowedKnownHttpMethodsStringList.get(3)) ); } else if (3 == allowedKnownHttpMethodsStringList.size()) { allowedKnownHttpMethods = EnumSet.of( HttpMethod.valueOf(allowedKnownHttpMethodsStringList.get(0)), HttpMethod.valueOf(allowedKnownHttpMethodsStringList.get(1)), HttpMethod.valueOf(allowedKnownHttpMethodsStringList.get(2)) ); } else if (2 == allowedKnownHttpMethodsStringList.size()) { allowedKnownHttpMethods = EnumSet.of( HttpMethod.valueOf(allowedKnownHttpMethodsStringList.get(0)), HttpMethod.valueOf(allowedKnownHttpMethodsStringList.get(1)) ); } else if (1 == allowedKnownHttpMethodsStringList.size()) { allowedKnownHttpMethods = EnumSet.of( HttpMethod.valueOf(allowedKnownHttpMethodsStringList.get(0)) ); } else { List restList = new ArrayList<>(allowedKnownHttpMethodsStringList.size() - 1); for (int i = 1; i < allowedKnownHttpMethodsStringList.size() - 1; i++) { restList.add(HttpMethod.valueOf( allowedKnownHttpMethodsStringList.get(i) )); } HttpMethod first = HttpMethod.valueOf(allowedKnownHttpMethodsStringList.get(0)); HttpMethod [] rest = new HttpMethod[restList.size()]; restList.toArray(rest); allowedKnownHttpMethods = EnumSet.of(first, rest); } } } private void uninitHttpMethodValidityVerification() { assert (null != allowedUnknownHttpMethods); assert (null != defaultAllowedHttpMethods); assert (null != allHttpMethods); allowedUnknownHttpMethods.clear(); allowedUnknownHttpMethods = null; allowedKnownHttpMethods.clear(); allowedKnownHttpMethods = null; allHttpMethods.clear(); allHttpMethods = null; } /** *

Process an incoming request, * and create the corresponding response according to the following * specification.

* *
* *

If the request and response * arguments to this method are not instances of * HttpServletRequest and * HttpServletResponse, respectively, the results of * invoking this method are undefined.

* *

This method must respond to requests that contain the following * strings by invoking the sendError method on the * response argument (cast to HttpServletResponse), * passing the code HttpServletResponse.SC_NOT_FOUND as * the argument.

* *

/WEB-INF/
/WEB-INF
/META-INF/
/META-INF
* * *

If none of the cases described above in the specification for * this method apply to the servicing of this request, the following * action must be taken to service the request.

*

Acquire a {@link FacesContext} instance for this request.

*

Acquire the ResourceHandler for this request by * calling {@link * javax.faces.application.Application#getResourceHandler}. Call * {@link * javax.faces.application.ResourceHandler#isResourceRequest}. If * this returns true call {@link * javax.faces.application.ResourceHandler#handleResourceRequest}. * If this returns false, call {@link * javax.faces.lifecycle.Lifecycle#attachWindow} followed by * {@link javax.faces.lifecycle.Lifecycle#execute} followed by * {@link javax.faces.lifecycle.Lifecycle#render}. If a {@link * javax.faces.FacesException} is thrown in either case, extract the * cause from the FacesException. If the cause is * null extract the message from the * FacesException, put it inside of a new * ServletException instance, and pass the * FacesException instance as the root cause, then * rethrow the ServletException instance. If the cause * is an instance of ServletException, rethrow the * cause. If the cause is an instance of IOException, * rethrow the cause. Otherwise, create a new * ServletException instance, passing the message from * the cause, as the first argument, and the cause itself as the * second argument.

*

The implementation must * make it so {@link javax.faces.context.FacesContext#release} is * called within a finally block as late as possible in the * processing for the JSF related portion of this request.

*
* * @param req The servlet request we are processing * @param resp The servlet response we are creating * * @throws IOException if an input/output error occurs during processing * @throws ServletException if a servlet error occurs during processing */ @Override public void service(ServletRequest req, ServletResponse resp) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; requestStart(request.getRequestURI()); // V3 Probe hook if (!isHttpMethodValid(request)) { response.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } if (Thread.currentThread().isInterrupted()) { if (LOGGER.isLoggable(Level.FINER)) { LOGGER.log(Level.FINE, "Thread {0} given to FacesServlet.service() in interrupted state", Thread.currentThread().getName()); } } // If prefix mapped, then ensure requests for /WEB-INF are // not processed. String pathInfo = request.getPathInfo(); if (pathInfo != null) { pathInfo = pathInfo.toUpperCase(); if (pathInfo.contains("/WEB-INF/") || pathInfo.contains("/WEB-INF") || pathInfo.contains("/META-INF/") || pathInfo.contains("/META-INF")) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } } if (!initFacesContextReleased) { FacesContext initFacesContext = FacesContext.getCurrentInstance(); if (null != initFacesContext) { initFacesContext.release(); } // Bug 20458755: ensure the special factory is removed, so as not // to incur an additional performance penalty at request processing // time. FactoryFinder.getFactory("com.sun.faces.ServletContextFacesContextFactory_Removal"); initFacesContextReleased = true; } // Acquire the FacesContext instance for this request FacesContext context = facesContextFactory.getFacesContext (servletConfig.getServletContext(), request, response, lifecycle); // Execute the request processing lifecycle for this request try { ResourceHandler handler = context.getApplication().getResourceHandler(); if (handler.isResourceRequest(context)) { handler.handleResourceRequest(context); } else { lifecycle.attachWindow(context); lifecycle.execute(context); lifecycle.render(context); } } catch (FacesException e) { Throwable t = e.getCause(); if (t == null) { throw new ServletException(e.getMessage(), e); } else { if (t instanceof ServletException) { throw ((ServletException) t); } else if (t instanceof IOException) { throw ((IOException) t); } else { throw new ServletException(t.getMessage(), t); } } } finally { // Release the FacesContext instance for this request context.release(); } requestEnd(); // V3 Probe hook } private boolean isHttpMethodValid(HttpServletRequest request) { boolean result = false; if (allowAllMethods) { result = true; } else { String requestMethodString = request.getMethod(); HttpMethod requestMethod = null; boolean isKnownHttpMethod; try { requestMethod = HttpMethod.valueOf(requestMethodString); isKnownHttpMethod = true; } catch (IllegalArgumentException e) { isKnownHttpMethod = false; } if (isKnownHttpMethod) { result = allowedKnownHttpMethods.contains(requestMethod); } else { result = allowedUnknownHttpMethods.contains(requestMethodString); } } return result; } // --------------------------------------------------------- Private Methods /** * DO NOT REMOVE. Necessary for V3 probe monitoring. */ @SuppressWarnings({"UnusedDeclaration"}) private void requestStart(String requestUri) { } /** * DO NOT REMOVE. Necessary for V3 probe monitoring. */ private void requestEnd() { } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy