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

org.apache.myfaces.webapp.filter.ExtensionsFilter Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.myfaces.webapp.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.renderkit.html.util.AddResource;
import org.apache.myfaces.renderkit.html.util.AddResourceFactory;

/**
 * This filter provides a number of functions that many tomahawk components require.
 * 

* In tomahawk versions up to and including 1.1.6, it is mandatory to define this filter in the application's * web.xml in order to use some tomahawk components. In Tomahawk version 1.1.7, this filter is now optional; * when defined it will be used as for earlier versions. When omitted, the same functionality is now * automatically provided via classes TomahawkFacesContextFactory and ServeResourcePhaseListener. * *

Response Buffering

* * When the request is for a JSF page, and the configured "resource manager" * requires response buffering then a response wrapper is created which * buffers the entire output from the current request in memory. *

* Tomahawk provides at least three "resource managers": *

    *
  • DefaultAddResources (the default) does require response buffering. *
  • NonBufferingAddResource does not require response buffering, but it * renders javascript on body and offer support in portlets enviroments. *
  • StreamingAddResources does not, but only provides a subset of the * features of DefaultAddResources and therefore does not work with all * Tomahawk components. *
*

* Only one "resource manager" may be configured for a webapp. See class * AddResourceFactory for further details on configuring this. *

* When DefaultAddResources is enabled (default behaviour), the resulting * response buffering does cause some unnecessary memory and performance * impact for pages where no component in the page actually registers a * resource that needs to be inserted into the page - but whether a page * does that or not cannot be known until after the page has been rendered. * In the rare case where a request to a JSF page generates non-html * output (eg a PDF is generated as a response to a submit of a jsf page), * the data is unfortunately buffered. However it is not post-processed, * because its http content-type header will not be "text/html" (see other * documentation for this class). * *

Inserting Resources into HTML responses (DefaultAddResources)

* * After the response has been completely generated (and cached in memory), * this filter checks the http content-type header. If it is not html or xhtml, * then the data is simply send to the response stream without further processing. * * For html or xhtml responses, this filter causes the data to be post-processed * to insert any "resources" registered via the AddResources framework. This * allows jsf components (and other code if it wants) to register data that * should be output into an HTML page, particularly into places like an html * "head" section, even when the component occurs after that part of the * response has been generated. *

* The default "resource manager" (DefaultAddResources) supports inserting * resources into any part of the generated page. The alternate class * StreamingAddResources does not; it does not buffer output and therefore * can only insert resources for a jsf component into the page after the * point at which that component is rendered. In particular, this means that * components that use external javascript files will not work with that * "resource manager" as [script href=...] only works in the head section * of an html page. * *

Serving Resources from the Classpath

* * Exactly what text gets inserted into an HTML page via a "resource" * (see above) is managed by the AddResources class, not this one. However * often it is useful for jsf components to be able to refer to resources * that are on the classpath, and in particular when the resource is in the * same jar as the component code. Servlet engines do not support serving * resources from the classpath. However the AddResources framework can be * used to generate a special url prefix that this filter can be mapped to, * allowing this to be done. In particular, many Tomahawk components use * this to bundle their necessary resources within the tomahawk jarfile. *

* When a request to such a url is found by this filter, the actual resource * is located and streamed back to the user (no buffering required). See the * AddResource class documentation for further details. * *

Handling File Uploads

* * Sometimes an application needs to allow a user to send a file of data * to the web application. The html page needs only to include an input * tag with type=file; clicking on this will prompt the user for a file * to send. The browser will then send an http request to the server * which is marked as a "mime multipart request" with normal http post * parameters in one mime part, and the file contents in another mime part. *

* This filter also handles such requests, using the Apache HttpClient * library to save the file into a configurable local directory before * allowing the normal processing for the url that the post request * refers to. A number of configuration properties on this filter control * maximum file upload sizes and various other useful settings. See the * documentation for the init method for more details. * *

Avoiding Processing

* * When the ExtensionsFilter is enabled, and the DefaultAddResources * implementation is used then there is no way to avoid having the * response buffered in memory. However as long as the mime-type set * for the response data is not text/html then the data will * be written out without any modifications. * * @author Sylvain Vieujot (latest modification by $Author: skitching $) * @version $Revision: 692393 $ $Date: 2008-09-05 04:26:40 -0500 (Fri, 05 Sep 2008) $ */ public class ExtensionsFilter implements Filter { private Log log = LogFactory.getLog(ExtensionsFilter.class); private int _uploadMaxFileSize = 100 * 1024 * 1024; // 100 MB private int _uploadThresholdSize = 1 * 1024 * 1024; // 1 MB private String _uploadRepositoryPath = null; //standard temp directory private ServletContext _servletContext; public static final String DOFILTER_CALLED = "org.apache.myfaces.component.html.util.ExtensionFilter.doFilterCalled"; /** * Init method for this filter. *

* The following filter init parameters can be configured in the web.xml file * for this filter: *

    *
  • uploadMaxFileSize
  • *
  • uploadThresholdSize
  • *
  • uploadRepositoryPath
  • *
*

*

* All size parameters may have the suffix "g" (gigabytes), "m" (megabytes) or "k" (kilobytes). *

* *

uploadMaxFileSize

* * Sets the maximum allowable size for uploaded files. *

* If the user attempts to upload a file which is larger than this, then the data is * transmitted from the browser to the server (this cannot be prevented with standard HTML * functionality). However the file will not be saved in memory or on disk. An error message * will be added to the standard JSF error messages, and the page re-rendered (as for a * validation failure). *

*

* The default value is 100 Megabytes. *

* *

uploadThresholdSize

* * Sets the size threshold beyond which files are written directly to disk. Files which are * smaller than this are simply held in memory. The default is 1 Megabyte. * *

uploadRepositoryPath

* * Sets the directory in which temporary files (ie caches for those uploaded files that * are larger than uploadThresholdSize) are to be stored. */ public void init(FilterConfig filterConfig) { // Note that the code here to extract FileUpload configuration params is not actually used. // The handling of multipart requests was moved from this Filter into a custom FacesContext // (TomahawkFacesContextWrapper) so that Portlets could be supported (Portlets cannot use // servlet filters). // // For backwards compatibility, the TomahawkFacesContextWrapper class *parses* the // web.xml to retrieve these same filter config params. That is IMO seriously ugly // and hopefully will be fixed. String param = filterConfig.getInitParameter("uploadMaxFileSize"); _uploadMaxFileSize = resolveSize(param, _uploadMaxFileSize); param = filterConfig.getInitParameter("uploadThresholdSize"); _uploadThresholdSize = resolveSize(param, _uploadThresholdSize); _uploadRepositoryPath = filterConfig.getInitParameter("uploadRepositoryPath"); _servletContext = filterConfig.getServletContext(); } private int resolveSize(String param, int defaultValue) { int numberParam = defaultValue; if (param != null) { param = param.toLowerCase(); int factor = 1; String number = param; if (param.endsWith("g")) { factor = 1024 * 1024 * 1024; number = param.substring(0, param.length() - 1); } else if (param.endsWith("m")) { factor = 1024 * 1024; number = param.substring(0, param.length() - 1); } else if (param.endsWith("k")) { factor = 1024; number = param.substring(0, param.length() - 1); } numberParam = Integer.parseInt(number) * factor; } return numberParam; } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if(request.getAttribute(DOFILTER_CALLED)!=null) { chain.doFilter(request, response); return; } request.setAttribute(DOFILTER_CALLED,"true"); if (!(response instanceof HttpServletResponse)) { //If this is a portlet request, just continue the chaining chain.doFilter(request, response); return; } HttpServletResponse httpResponse = (HttpServletResponse) response; HttpServletRequest httpRequest = (HttpServletRequest) request; // Serve resources AddResource addResource; try { addResource = AddResourceFactory.getInstance(httpRequest,_servletContext); if( addResource.isResourceUri(_servletContext, httpRequest ) ){ addResource.serveResource(_servletContext, httpRequest, httpResponse); return; } } catch(Throwable th) { log.error("Exception wile retrieving addResource",th); throw new ServletException(th); } HttpServletRequest extendedRequest = httpRequest; // For multipart/form-data requests // This is done by TomahawkFacesContextWrapper if (FileUpload.isMultipartContent(httpRequest)) { extendedRequest = new MultipartRequestWrapper(httpRequest, _uploadMaxFileSize, _uploadThresholdSize, _uploadRepositoryPath); } try { addResource.responseStarted(); //This case is necessary when is used //org.apache.myfaces.renderkit.html.util.DefaultAddResource //Buffers the output and add to the header the necessary stuff //In other case this is simply ignored (NonBufferingAddResource and //StreamingAddResource), because this not require buffering //and the chaining continues. if (addResource.requiresBuffer()) { ExtensionsResponseWrapper extendedResponse = new ExtensionsResponseWrapper((HttpServletResponse) response); // Standard request chain.doFilter(extendedRequest, extendedResponse); extendedResponse.finishResponse(); // write the javascript stuff for myfaces and headerInfo, if needed HttpServletResponse servletResponse = (HttpServletResponse)response; // only parse HTML responses if (extendedResponse.getContentType() != null && isValidContentType(extendedResponse.getContentType())) { addResource.parseResponse(extendedRequest, extendedResponse.toString(), servletResponse); addResource.writeMyFacesJavascriptBeforeBodyEnd(extendedRequest, servletResponse); if( ! addResource.hasHeaderBeginInfos() ){ // writes the response if no header info is needed addResource.writeResponse(extendedRequest, servletResponse); return; } // Some headerInfo has to be added addResource.writeWithFullHeader(extendedRequest, servletResponse); // writes the response addResource.writeResponse(extendedRequest, servletResponse); } else { byte[] responseArray = extendedResponse.getBytes(); if(responseArray.length > 0) { // When not filtering due to not valid content-type, deliver the byte-array instead of a charset-converted string. // Otherwise a binary stream gets corrupted. servletResponse.getOutputStream().write(responseArray); } } } else { chain.doFilter(extendedRequest, response); } } finally { addResource.responseFinished(); } //chain.doFilter(extendedRequest, response); } public boolean isValidContentType(String contentType) { return contentType.startsWith("text/html") || contentType.startsWith("text/xml") || contentType.startsWith("application/xhtml+xml") || contentType.startsWith("application/xml"); } /** * Destroy method for this filter */ public void destroy() { // NoOp } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy