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.http;
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
035public class 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
047   *                   client.
048   */
049  public MasterRedirectServlet(InfoServer infoServer, String hostname) {
050    regionServerInfoPort = infoServer.getPort();
051    regionServerHostname = hostname;
052  }
053
054  @Override
055  public void doGet(HttpServletRequest request, HttpServletResponse response)
056    throws ServletException, IOException {
057    String redirectHost = regionServerHostname;
058    if (redirectHost == null) {
059      redirectHost = request.getServerName();
060      if (!Addressing.isLocalAddress(InetAddress.getByName(redirectHost))) {
061        LOG.warn("Couldn't resolve '" + redirectHost + "' as an address local to this node and '"
062          + MASTER_HOSTNAME_KEY + "' is not set; client will get an HTTP 400 response. If "
063          + "your HBase deployment relies on client accessible names that the region server "
064          + "process can't resolve locally, then you should set the previously mentioned "
065          + "configuration variable to an appropriate hostname.");
066        // no sending client provided input back to the client, so the goal host is just in the
067        // logs.
068        response.sendError(400,
069          "Request was to a host that I can't resolve for any of the network interfaces on "
070            + "this node. If this is due to an intermediary such as an HTTP load balancer or "
071            + "other proxy, your HBase administrator can set '" + MASTER_HOSTNAME_KEY
072            + "' to point to the correct hostname.");
073        return;
074      }
075    }
076    // TODO: this scheme should come from looking at the scheme registered in the infoserver's http
077    // server for the host and port we're using, but it's buried way too deep to do that ATM.
078    String redirectUrl = request.getScheme() + "://" + redirectHost + ":" + regionServerInfoPort
079      + request.getRequestURI();
080    response.sendRedirect(redirectUrl);
081  }
082}