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.HashMap;
    19  import java.util.Map;
    20  import java.util.regex.Matcher;
    21  import java.util.regex.Pattern;
    22
    23  import javax.servlet.Filter;
    24  import javax.servlet.FilterChain;
    25  import javax.servlet.FilterConfig;
    26  import javax.servlet.ServletException;
    27  import javax.servlet.ServletRequest;
    28  import javax.servlet.ServletResponse;
    29  import javax.servlet.http.HttpServletRequest;
    30
    31  /* ------------------------------------------------------------ */
    32  /** User Agent Filter.
    33   * <p>
    34   * This filter allows efficient matching of user agent strings for
    35   * downstream or extended filters to use for browser specific logic.
    36   * </p>
    37   * <p>
    38   * The filter is configured with the following init parameters:
    39   * <dl>
    40   * <dt>attribute</dt><dd>If set, then the request attribute of this name is set with the matched user agent string</dd>
    41   * <dt>cacheSize</dt><dd>The size of the user-agent cache, used to avoid reparsing of user agent strings. The entire cache is flushed
    42   * when this size is reached</dd>
    43   * <dt>userAgent</dt><dd>A regex {@link Pattern} to extract the essential elements of the user agent.
    44   * The concatenation of matched pattern groups is used as the user agent name</dd>
    45   * <dl>
    46   * An example value for pattern is <code>(?:Mozilla[^\(]*\(compatible;\s*+([^;]*);.*)|(?:.*?([^\s]+/[^\s]+).*)</code>. These two
    47   * pattern match the common compatibility user-agent strings and extract the real user agent, failing that, the first
    48   * element of the agent string is returned.
    49   * @author gregw
    50   *
    51   */
    52  public class UserAgentFilter implements Filter
    53  {
    54      private Pattern _pattern;
    55      private Map _agentCache = new HashMap();
    56      private int _agentCacheSize=1024;
    57      private String _attribute;
    58
    59      /* ------------------------------------------------------------ */
    60      /* (non-Javadoc)
    61       * @see javax.servlet.Filter#destroy()
    62       */
    63      public void destroy()
    64      {
    65      }
    66
    67      /* ------------------------------------------------------------ */
    68      /* (non-Javadoc)
    69       * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
    70       */
    71      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
    72      {
    73          if (_attribute!=null && _pattern!=null)
    74          {
    75              String ua=getUserAgent(request);
    76              request.setAttribute(_attribute,ua);
    77          }
    78          chain.doFilter(request,response);
    79      }
    80
    81      /* ------------------------------------------------------------ */
    82      /* (non-Javadoc)
    83       * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
    84       */
    85      public void init(FilterConfig filterConfig) throws ServletException
    86      {
    87          _attribute=filterConfig.getInitParameter("attribute");
    88
    89          String p=filterConfig.getInitParameter("userAgent");
    90          if (p!=null)
    91              _pattern=Pattern.compile(p);
    92
    93          String size=filterConfig.getInitParameter("cacheSize");
    94          if (size!=null)
    95              _agentCacheSize=Integer.parseInt(size);
    96      }
    97
    98      /* ------------------------------------------------------------ */
    99      public String getUserAgent(ServletRequest request)
    100     {
    101         String ua=((HttpServletRequest)request).getHeader("User-Agent");
    102         return getUserAgent(ua);
    103     }
    104
    105     /* ------------------------------------------------------------ */
    106     /** Get UserAgent.
    107      * The configured agent patterns are used to match against the passed user agent string.
    108      * If any patterns match, the concatenation of pattern groups is returned as the user agent
    109      * string. Match results are cached.
    110      * @param ua A user agent string
    111      * @return The matched pattern groups or the original user agent string
    112      */
    113     public String getUserAgent(String ua)
    114     {
    115         if (ua==null)
    116             return null;
    117
    118         String tag;
    119         synchronized(_agentCache)
    120         {
    121             tag = (String)_agentCache.get(ua);
    122         }
    123
    124         if (tag==null)
    125         {
    126             Matcher matcher=_pattern.matcher(ua);
    127             if (matcher.matches())
    128             {
    129                 if(matcher.groupCount()>0)
    130                 {
    131                     for (int g=1;g<=matcher.groupCount();g++)
    132                     {
    133                         String group=matcher.group(g);
    134                         if (group!=null)
    135                             tag=tag==null?group:(tag+group);
    136                     }
    137                 }
    138                 else
    139                     tag=matcher.group();
    140             }
    141             else
    142                 tag=ua;
    143
    144             synchronized(_agentCache)
    145             {
    146                 if (_agentCache.size()>=_agentCacheSize)
    147                     _agentCache.clear();
    148                 _agentCache.put(ua,tag);
    149             }
    150
    151         }
    152         return tag;
    153     }
    154 }