| <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>OncePerRequestFilter.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Apache Shiro :: Web</a> > <a href="index.source.html" class="el_package">org.apache.shiro.web.servlet</a> > <span class="el_source">OncePerRequestFilter.java</span></div><h1>OncePerRequestFilter.java</h1><pre class="source lang-java linenums">/* |
| * 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.shiro.web.servlet; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import javax.servlet.FilterChain; |
| import javax.servlet.ServletException; |
| import javax.servlet.ServletRequest; |
| import javax.servlet.ServletResponse; |
| import java.io.IOException; |
| |
| /** |
| * Filter base class that guarantees to be just executed once per request, |
| * on any servlet container. It provides a {@link #doFilterInternal} |
| * method with HttpServletRequest and HttpServletResponse arguments. |
| * <p/> |
| * The {@link #getAlreadyFilteredAttributeName} method determines how |
| * to identify that a request is already filtered. The default implementation |
| * is based on the configured name of the concrete filter instance. |
| * <h3>Controlling filter execution</h3> |
| * 1.2 introduced the {@link #isEnabled(javax.servlet.ServletRequest, javax.servlet.ServletResponse)} method and |
| * {@link #isEnabled()} property to allow explicit controll over whether the filter executes (or allows passthrough) |
| * for any given request. |
| * <p/> |
| * <b>NOTE</b> This class was initially borrowed from the Spring framework but has continued modifications. |
| * |
| * @since 0.1 |
| */ |
| <span class="fc" id="L47">public abstract class OncePerRequestFilter extends NameableFilter {</span> |
| |
| /** |
| * Private internal log instance. |
| */ |
| <span class="fc" id="L52"> private static final Logger log = LoggerFactory.getLogger(OncePerRequestFilter.class);</span> |
| |
| /** |
| * Suffix that gets appended to the filter name for the "already filtered" request attribute. |
| * |
| * @see #getAlreadyFilteredAttributeName |
| */ |
| public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED"; |
| |
| /** |
| * Determines generally if this filter should execute or let requests fall through to the next chain element. |
| * |
| * @see #isEnabled() |
| */ |
| <span class="fc" id="L66"> private boolean enabled = true; //most filters wish to execute when configured, so default to true</span> |
| |
| /** |
| * Returns {@code true} if this filter should <em>generally</em><b>*</b> execute for any request, |
| * {@code false} if it should let the request/response pass through immediately to the next |
| * element in the {@link FilterChain}. The default value is {@code true}, as most filters would inherently need |
| * to execute when configured. |
| * <p/> |
| * <b>*</b> This configuration property is for general configuration for any request that comes through |
| * the filter. The |
| * {@link #isEnabled(javax.servlet.ServletRequest, javax.servlet.ServletResponse) isEnabled(request,response)} |
| * method actually determines whether or not if the filter is enabled based on the current request. |
| * |
| * @return {@code true} if this filter should <em>generally</em> execute, {@code false} if it should let the |
| * request/response pass through immediately to the next element in the {@link FilterChain}. |
| * @since 1.2 |
| */ |
| public boolean isEnabled() { |
| <span class="fc" id="L84"> return enabled;</span> |
| } |
| |
| /** |
| * Sets whether or not this filter <em>generally</em> executes for any request. See the |
| * {@link #isEnabled() isEnabled()} JavaDoc as to what <em>general</em> execution means. |
| * |
| * @param enabled whether or not this filter <em>generally</em> executes. |
| * @since 1.2 |
| */ |
| public void setEnabled(boolean enabled) { |
| <span class="fc" id="L95"> this.enabled = enabled;</span> |
| <span class="fc" id="L96"> }</span> |
| |
| /** |
| * This {@code doFilter} implementation stores a request attribute for |
| * "already filtered", proceeding without filtering again if the |
| * attribute is already there. |
| * |
| * @see #getAlreadyFilteredAttributeName |
| * @see #shouldNotFilter |
| * @see #doFilterInternal |
| */ |
| public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) |
| throws ServletException, IOException { |
| <span class="fc" id="L109"> String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();</span> |
| <span class="pc bpc" id="L110" title="1 of 2 branches missed."> if ( request.getAttribute(alreadyFilteredAttributeName) != null ) {</span> |
| <span class="nc" id="L111"> log.trace("Filter '{}' already executed. Proceeding without invoking this filter.", getName());</span> |
| <span class="nc" id="L112"> filterChain.doFilter(request, response);</span> |
| } else //noinspection deprecation |
| <span class="fc bfc" id="L114" title="All 2 branches covered."> if (/* added in 1.2: */ !isEnabled(request, response) ||</span> |
| <span class="pc bpc" id="L115" title="1 of 2 branches missed."> /* retain backwards compatibility: */ shouldNotFilter(request) ) {</span> |
| <span class="fc" id="L116"> log.debug("Filter '{}' is not enabled for the current request. Proceeding without invoking this filter.",</span> |
| <span class="fc" id="L117"> getName());</span> |
| <span class="fc" id="L118"> filterChain.doFilter(request, response);</span> |
| } else { |
| // Do invoke this filter... |
| <span class="fc" id="L121"> log.trace("Filter '{}' not yet executed. Executing now.", getName());</span> |
| <span class="fc" id="L122"> request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);</span> |
| |
| try { |
| <span class="fc" id="L125"> doFilterInternal(request, response, filterChain);</span> |
| } finally { |
| // Once the request has finished, we're done and we don't |
| // need to mark as 'already filtered' any more. |
| <span class="fc" id="L129"> request.removeAttribute(alreadyFilteredAttributeName);</span> |
| } |
| } |
| <span class="fc" id="L132"> }</span> |
| |
| /** |
| * Returns {@code true} if this filter should filter the specified request, {@code false} if it should let the |
| * request/response pass through immediately to the next element in the {@code FilterChain}. |
| * <p/> |
| * This default implementation merely returns the value of {@link #isEnabled() isEnabled()}, which is |
| * {@code true} by default (to ensure the filter always executes by default), but it can be overridden by |
| * subclasses for request-specific behavior if necessary. For example, a filter could be enabled or disabled |
| * based on the request path being accessed. |
| * <p/> |
| * <b>Helpful Hint:</b> if your subclass extends {@link org.apache.shiro.web.filter.PathMatchingFilter PathMatchingFilter}, |
| * you may wish to instead override the |
| * {@link org.apache.shiro.web.filter.PathMatchingFilter#isEnabled(javax.servlet.ServletRequest, javax.servlet.ServletResponse, String, Object) |
| * PathMatchingFilter.isEnabled(request,response,path,pathSpecificConfig)} |
| * method if you want to make your enable/disable decision based on any path-specific configuration. |
| * |
| * @param request the incoming servlet request |
| * @param response the outbound servlet response |
| * @return {@code true} if this filter should filter the specified request, {@code false} if it should let the |
| * request/response pass through immediately to the next element in the {@code FilterChain}. |
| * @throws IOException in the case of any IO error |
| * @throws ServletException in the case of any error |
| * @see org.apache.shiro.web.filter.PathMatchingFilter#isEnabled(javax.servlet.ServletRequest, javax.servlet.ServletResponse, String, Object) |
| * @since 1.2 |
| */ |
| @SuppressWarnings({"UnusedParameters"}) |
| protected boolean isEnabled(ServletRequest request, ServletResponse response) throws ServletException, IOException { |
| <span class="fc" id="L160"> return isEnabled();</span> |
| } |
| |
| /** |
| * Return name of the request attribute that identifies that a request has already been filtered. |
| * <p/> |
| * The default implementation takes the configured {@link #getName() name} and appends &quot;{@code .FILTERED}&quot;. |
| * If the filter is not fully initialized, it falls back to the implementation's class name. |
| * |
| * @return the name of the request attribute that identifies that a request has already been filtered. |
| * @see #getName |
| * @see #ALREADY_FILTERED_SUFFIX |
| */ |
| protected String getAlreadyFilteredAttributeName() { |
| <span class="fc" id="L174"> String name = getName();</span> |
| <span class="pc bpc" id="L175" title="1 of 2 branches missed."> if (name == null) {</span> |
| <span class="nc" id="L176"> name = getClass().getName();</span> |
| } |
| <span class="fc" id="L178"> return name + ALREADY_FILTERED_SUFFIX;</span> |
| } |
| |
| /** |
| * Can be overridden in subclasses for custom filtering control, |
| * returning <code>true</code> to avoid filtering of the given request. |
| * <p>The default implementation always returns <code>false</code>. |
| * |
| * @param request current HTTP request |
| * @return whether the given request should <i>not</i> be filtered |
| * @throws ServletException in case of errors |
| * @deprecated in favor of overriding {@link #isEnabled(javax.servlet.ServletRequest, javax.servlet.ServletResponse)} |
| * for custom behavior. This method will be removed in Shiro 2.0. |
| */ |
| @Deprecated |
| @SuppressWarnings({"UnusedDeclaration"}) |
| protected boolean shouldNotFilter(ServletRequest request) throws ServletException { |
| <span class="fc" id="L195"> return false;</span> |
| } |
| |
| |
| /** |
| * Same contract as for |
| * {@link #doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)}, |
| * but guaranteed to be invoked only once per request. |
| * |
| * @param request incoming {@code ServletRequest} |
| * @param response outgoing {@code ServletResponse} |
| * @param chain the {@code FilterChain} to execute |
| * @throws ServletException if there is a problem processing the request |
| * @throws IOException if there is an I/O problem processing the request |
| */ |
| protected abstract void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) |
| throws ServletException, IOException; |
| } |
| </pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.3.201901230119</span></div></body></html> |