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 */
018package org.apache.hadoop.hbase.master;
019
020import static org.apache.hadoop.hbase.util.DNS.MASTER_HOSTNAME_KEY;
021
022import java.io.IOException;
023import java.net.InetAddress;
024import javax.servlet.ServletException;
025import javax.servlet.http.HttpServlet;
026import javax.servlet.http.HttpServletRequest;
027import javax.servlet.http.HttpServletResponse;
028import org.apache.hadoop.hbase.http.InfoServer;
029import org.apache.hadoop.hbase.util.Addressing;
030import org.apache.yetus.audience.InterfaceAudience;
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
033
034@InterfaceAudience.Private
035class MasterRedirectServlet extends HttpServlet {
036
037  private static final long serialVersionUID = 2894774810058302473L;
038
039  private static final Logger LOG = LoggerFactory.getLogger(MasterRedirectServlet.class);
040
041  private final int regionServerInfoPort;
042  private final String regionServerHostname;
043
044  /**
045   * @param infoServer that we're trying to send all requests to
046   * @param hostname may be null. if given, will be used for redirects instead of host from client.
047   */
048  public MasterRedirectServlet(InfoServer infoServer, String hostname) {
049    regionServerInfoPort = infoServer.getPort();
050    regionServerHostname = hostname;
051  }
052
053  @Override
054  public void doGet(HttpServletRequest request, HttpServletResponse response)
055    throws ServletException, IOException {
056    String redirectHost = regionServerHostname;
057    if (redirectHost == null) {
058      redirectHost = request.getServerName();
059      if (!Addressing.isLocalAddress(InetAddress.getByName(redirectHost))) {
060        LOG.warn("Couldn't resolve '" + redirectHost + "' as an address local to this node and '" +
061          MASTER_HOSTNAME_KEY + "' is not set; client will get an HTTP 400 response. If " +
062          "your HBase deployment relies on client accessible names that the region server " +
063          "process can't resolve locally, then you should set the previously mentioned " +
064          "configuration variable to an appropriate hostname.");
065        // no sending client provided input back to the client, so the goal host is just in the
066        // logs.
067        response.sendError(400,
068          "Request was to a host that I can't resolve for any of the network interfaces on " +
069            "this node. If this is due to an intermediary such as an HTTP load balancer or " +
070            "other proxy, your HBase administrator can set '" + MASTER_HOSTNAME_KEY +
071            "' to point to the correct hostname.");
072        return;
073      }
074    }
075    // TODO: this scheme should come from looking at the scheme registered in the infoserver's http
076    // server for the host and port we're using, but it's buried way too deep to do that ATM.
077    String redirectUrl = request.getScheme() + "://" + redirectHost + ":" + regionServerInfoPort +
078      request.getRequestURI();
079    response.sendRedirect(redirectUrl);
080  }
081}