View Javadoc

    1   // ========================================================================
    2   // Copyright 2006 Mort Bay Consulting Pty. Ltd.
    3   // ------------------------------------------------------------------------
    4   // Licensed under the Apache License, Version 2.0 (the "License");
    5   // you may not use this file except in compliance with the License.
    6   // You may obtain a copy of the License at
    7   // http://www.apache.org/licenses/LICENSE-2.0
    8   // Unless required by applicable law or agreed to in writing, software
    9   // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  // ========================================================================
    14
    15  package org.mortbay.servlet;
    16
    17  import java.io.IOException;
    18  import java.util.ArrayList;
    19  import java.util.Enumeration;
    20  import java.util.HashMap;
    21  import java.util.List;
    22  import java.util.Map;
    23  import java.util.regex.Matcher;
    24  import java.util.regex.Pattern;
    25
    26  import javax.servlet.Filter;
    27  import javax.servlet.FilterChain;
    28  import javax.servlet.FilterConfig;
    29  import javax.servlet.ServletException;
    30  import javax.servlet.ServletRequest;
    31  import javax.servlet.ServletResponse;
    32  import javax.servlet.http.HttpServletRequest;
    33
    34  /* ------------------------------------------------------------ */
    35  /** User Agent Filter.
    36   * <p>
    37   * This filter allows efficient matching of user agent strings for
    38   * downstream or extended filters to use for browser specific logic.
    39   * </p>
    40   * <p>
    41   * The filter is configured with the following init parameters:
    42   * <dl>
    43   * <dt>attribute</dt><dd>If set, then the request attribute of this name is set with the matched user agent string</dd>
    44   * <dt>cacheSize</dt><dd>The size of the user-agent cache, used to avoid reparsing of user agent strings. The entire cache is flushed
    45   * when this size is reached</dd>
    46   * <dt>userAgent</dt><dd>A regex {@link Pattern} to extract the essential elements of the user agent.
    47   * The concatenation of matched pattern groups is used as the user agent name</dd>
    48   * <dl>
    49   * An example value for pattern is <code>(?:Mozilla[^\(]*\(compatible;\s*+([^;]*);.*)|(?:.*?([^\s]+/[^\s]+).*)</code>. These two
    50   * pattern match the common compatibility user-agent strings and extract the real user agent, failing that, the first
    51   * element of the agent string is returned.
    52   * @author gregw
    53   *
    54   */
    55  public class UserAgentFilter implements Filter
    56  {
    57      private Pattern _pattern;
    58      private Map _agentCache = new HashMap();
    59      private int _agentCacheSize=1024;
    60      private String _attribute;
    61
    62      /* ------------------------------------------------------------ */
    63      /* (non-Javadoc)
    64       * @see javax.servlet.Filter#destroy()
    65       */
    66      public void destroy()
    67      {
    68      }
    69
    70      /* ------------------------------------------------------------ */
    71      /* (non-Javadoc)
    72       * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
    73       */
    74      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
    75      {
    76          if (_attribute!=null && _pattern!=null)
    77          {
    78              String ua=getUserAgent(request);
    79              request.setAttribute(_attribute,ua);
    80          }
    81          chain.doFilter(request,response);
    82      }
    83
    84      /* ------------------------------------------------------------ */
    85      /* (non-Javadoc)
    86       * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
    87       */
    88      public void init(FilterConfig filterConfig) throws ServletException
    89      {
    90          _attribute=filterConfig.getInitParameter("attribute");
    91
    92          String p=filterConfig.getInitParameter("userAgent");
    93          if (p!=null)
    94              _pattern=Pattern.compile(p);
    95
    96          String size=filterConfig.getInitParameter("cacheSize");
    97          if (size!=null)
    98              _agentCacheSize=Integer.parseInt(size);
    99      }
    100
    101     /* ------------------------------------------------------------ */
    102     public String getUserAgent(ServletRequest request)
    103     {
    104         String ua=((HttpServletRequest)request).getHeader("User-Agent");
    105         return getUserAgent(ua);
    106     }
    107
    108     /* ------------------------------------------------------------ */
    109     /** Get UserAgent.
    110      * The configured agent patterns are used to match against the passed user agent string.
    111      * If any patterns match, the concatenation of pattern groups is returned as the user agent
    112      * string. Match results are cached.
    113      * @param ua A user agent string
    114      * @return The matched pattern groups or the original user agent string
    115      */
    116     public String getUserAgent(String ua)
    117     {
    118         if (ua==null)
    119             return null;
    120
    121         String tag;
    122         synchronized(_agentCache)
    123         {
    124             tag = (String)_agentCache.get(ua);
    125         }
    126
    127         if (tag==null)
    128         {
    129             Matcher matcher=_pattern.matcher(ua);
    130             if (matcher.matches())
    131             {
    132                 if(matcher.groupCount()>0)
    133                 {
    134                     for (int g=1;g<=matcher.groupCount();g++)
    135                     {
    136                         String group=matcher.group(g);
    137                         if (group!=null)
    138                             tag=tag==null?group:(tag+group);
    139                     }
    140                 }
    141                 else
    142                     tag=matcher.group();
    143             }
    144             else
    145                 tag=ua;
    146
    147             synchronized(_agentCache)
    148             {
    149                 if (_agentCache.size()>=_agentCacheSize)
    150                     _agentCache.clear();
    151                 _agentCache.put(ua,tag);
    152             }
    153
    154         }
    155         return tag;
    156     }
    157 }