001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package org.apache.hadoop.lib.servlet;
020    
021    
022    import org.apache.hadoop.classification.InterfaceAudience;
023    
024    import javax.servlet.Filter;
025    import javax.servlet.FilterChain;
026    import javax.servlet.FilterConfig;
027    import javax.servlet.ServletException;
028    import javax.servlet.ServletRequest;
029    import javax.servlet.ServletResponse;
030    import java.io.IOException;
031    import java.net.InetAddress;
032    import java.net.UnknownHostException;
033    import org.slf4j.Logger;
034    import org.slf4j.LoggerFactory;
035    
036    /**
037     * Filter that resolves the requester hostname.
038     */
039    @InterfaceAudience.Private
040    public class HostnameFilter implements Filter {
041      static final ThreadLocal<String> HOSTNAME_TL = new ThreadLocal<String>();
042      private static final Logger log = LoggerFactory.getLogger(HostnameFilter.class);
043    
044      /**
045       * Initializes the filter.
046       * <p/>
047       * This implementation is a NOP.
048       *
049       * @param config filter configuration.
050       *
051       * @throws ServletException thrown if the filter could not be initialized.
052       */
053      @Override
054      public void init(FilterConfig config) throws ServletException {
055      }
056    
057      /**
058       * Resolves the requester hostname and delegates the request to the chain.
059       * <p/>
060       * The requester hostname is available via the {@link #get} method.
061       *
062       * @param request servlet request.
063       * @param response servlet response.
064       * @param chain filter chain.
065       *
066       * @throws IOException thrown if an IO error occurrs.
067       * @throws ServletException thrown if a servet error occurrs.
068       */
069      @Override
070      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
071        throws IOException, ServletException {
072        try {
073          String hostname;
074          try {
075            String address = request.getRemoteAddr();
076            if (address != null) {
077              hostname = InetAddress.getByName(address).getCanonicalHostName();
078            } else {
079              log.warn("Request remote address is NULL");
080              hostname = "???";
081            }
082          } catch (UnknownHostException ex) {
083            log.warn("Request remote address could not be resolved, {0}", ex.toString(), ex);
084            hostname = "???";
085          }
086          HOSTNAME_TL.set(hostname);
087          chain.doFilter(request, response);
088        } finally {
089          HOSTNAME_TL.remove();
090        }
091      }
092    
093      /**
094       * Returns the requester hostname.
095       *
096       * @return the requester hostname.
097       */
098      public static String get() {
099        return HOSTNAME_TL.get();
100      }
101    
102      /**
103       * Destroys the filter.
104       * <p/>
105       * This implementation is a NOP.
106       */
107      @Override
108      public void destroy() {
109      }
110    }