View Javadoc
1   /*
2    * Copyright (c) 2002-2014, Mairie de Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.portal.service.filter;
35  
36  import fr.paris.lutece.portal.service.util.AppLogService;
37  import fr.paris.lutece.util.sql.TransactionManager;
38  
39  import java.io.IOException;
40  
41  import javax.servlet.Filter;
42  import javax.servlet.FilterChain;
43  import javax.servlet.FilterConfig;
44  import javax.servlet.ServletException;
45  import javax.servlet.ServletRequest;
46  import javax.servlet.ServletResponse;
47  import javax.servlet.http.HttpServletRequest;
48  import javax.servlet.http.HttpServletResponse;
49  
50  
51  /**
52   * MainFilter
53   */
54  public class MainFilter implements Filter
55  {
56      /**
57       * {@inheritDoc}
58       */
59      public void init( FilterConfig config ) throws ServletException
60      {
61          FilterService.setServletContext( config.getServletContext(  ) );
62      }
63  
64      /**
65       * {@inheritDoc}
66       */
67      public void doFilter( ServletRequest requestServlet, ServletResponse responseServlet, FilterChain chain )
68          throws IOException, ServletException
69      {
70          AppLogService.debug( "MainFilter : doFilter()" );
71  
72          HttpServletRequest request = (HttpServletRequest) requestServlet;
73          HttpServletResponse response = (HttpServletResponse) responseServlet;
74          LuteceFilterChain chainPluginsFilters = new LuteceFilterChain(  );
75  
76          for ( LuteceFilter filter : FilterService.getInstance(  ).getFilters(  ) )
77          {
78              AppLogService.debug( "PluginFilter : " + filter.getName(  ) + " - url pattern : " +
79                  filter.getMappingUrlPattern(  ) );
80  
81              // Catch exception for each filter to execute all chain
82              try
83              {
84                  // Checks mapping and plugin status
85                  if ( matchMapping( filter, request ) && filter.getPlugin(  ).isInstalled(  ) )
86                  {
87                      chainPluginsFilters.setFollowChain( false );
88                      filter.getFilter(  ).doFilter( request, response, chainPluginsFilters );
89  
90                      if ( !chainPluginsFilters.shouldFollowChain(  ) )
91                      {
92                          // The filter didn't call chain.doFilter so the chain should be interrupted
93                          return;
94                      }
95  
96                      // the filter may have changed (wrapped) the request [like CAS filter] or the response
97                      request = (HttpServletRequest) chainPluginsFilters.getRequest(  );
98                      response = (HttpServletResponse) chainPluginsFilters.getResponse(  );
99                  }
100             }
101             catch ( Exception e )
102             {
103                 AppLogService.error( "Error execution doFilter method - Filter " + filter.getName(  ), e );
104             }
105         }
106 
107         // Follow the standard filters chain
108         chain.doFilter( request, response );
109         // We check that some transactions is not still running for the current thread
110         TransactionManager.rollBackEveryTransaction(  );
111     }
112 
113     /**
114      * {@inheritDoc}
115      */
116     public void destroy(  )
117     {
118         for ( LuteceFilter filter : FilterService.getInstance(  ).getFilters(  ) )
119         {
120             // Catch exception for each filter to execute all chain
121             try
122             {
123                 // Checks mapping and plugin status
124                 if ( filter.getPlugin(  ).isInstalled(  ) )
125                 {
126                     filter.getFilter(  ).destroy(  );
127                 }
128             }
129             catch ( Exception e )
130             {
131                 AppLogService.error( "Error execution destroy() method - Filter " + filter.getName(  ), e );
132             }
133         }
134     }
135 
136     /**
137      * Check the mapping of the request with an url pattern
138      * @param filter The filter
139      * @param request The request
140      * @return True if the request match the url pattern
141      */
142     boolean matchMapping( LuteceFilter filter, HttpServletRequest request )
143     {
144         return matchFilterUrl( filter.getMappingUrlPattern(  ), request.getServletPath(  ) );
145     }
146 
147     /**
148      * Check the mapping of the request with an url pattern according servlet
149      * specifications 2.3 rules
150      * @param strUrlPattern The filter url pattern
151      * @param strRequestUrl The request Url
152      * @return True if the request match the url pattern
153      *
154      *         Algorithm comming from tomcat6
155      */
156     boolean matchFilterUrl( String strUrlPattern, String strRequestUrl )
157     {
158         if ( strUrlPattern == null )
159         {
160             return ( false ); // Case 1 - Exact Match
161         }
162 
163         if ( strUrlPattern.equals( strRequestUrl ) )
164         {
165             return ( true ); // Case 2 - Path Match ("/.../*")
166         }
167 
168         if ( strUrlPattern.equals( "/*" ) )
169         {
170             return ( true );
171         }
172 
173         if ( strUrlPattern.endsWith( "/*" ) )
174         {
175             if ( strUrlPattern.regionMatches( 0, strRequestUrl, 0, strUrlPattern.length(  ) - 2 ) )
176             {
177                 if ( strRequestUrl.length(  ) == ( strUrlPattern.length(  ) - 2 ) )
178                 {
179                     return ( true );
180                 }
181                 else if ( '/' == strRequestUrl.charAt( strUrlPattern.length(  ) - 2 ) )
182                 {
183                     return ( true );
184                 }
185             }
186 
187             return ( false );
188         }
189 
190         // Case 3 - Extension Match
191         if ( strUrlPattern.startsWith( "*." ) )
192         {
193             int slash = strRequestUrl.lastIndexOf( '/' );
194             int period = strRequestUrl.lastIndexOf( '.' );
195 
196             if ( ( slash >= 0 ) && ( period > slash ) && ( period != ( strRequestUrl.length(  ) - 1 ) ) &&
197                     ( ( strRequestUrl.length(  ) - period ) == ( strUrlPattern.length(  ) - 1 ) ) )
198             {
199                 return ( strUrlPattern.regionMatches( 2, strRequestUrl, period + 1, strUrlPattern.length(  ) - 2 ) );
200             }
201         }
202 
203         // Case 4 - "Default" Match
204         return ( false ); // NOTE - Not relevant for selecting filters
205     }
206 }