/** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.aurora.scheduler.http; import java.io.IOException; import java.util.Objects; import javax.inject.Inject; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.core.HttpHeaders; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; import com.google.common.io.Resources; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.apache.aurora.gen.apiConstants.BYPASS_LEADER_REDIRECT_HEADER_NAME; import static org.apache.aurora.scheduler.http.LeaderRedirect.LeaderStatus; /** * An HTTP filter that will redirect the request to the leading scheduler. */ public class LeaderRedirectFilter extends AbstractFilter { private static final Logger LOG = LoggerFactory.getLogger(LeaderRedirectFilter.class); @VisibleForTesting static final String NO_LEADER_PAGE = "no-leader.html"; private final LeaderRedirect redirector; @Inject LeaderRedirectFilter(LeaderRedirect redirector) { this.redirector = Objects.requireNonNull(redirector); } private void sendServiceUnavailable(HttpServletResponse response) throws IOException { response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE); Resources.asByteSource(Resources.getResource(LeaderRedirectFilter.class, NO_LEADER_PAGE)) .copyTo(response.getOutputStream()); } @Override public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { if (request.getHeader(BYPASS_LEADER_REDIRECT_HEADER_NAME) != null) { LOG.info(BYPASS_LEADER_REDIRECT_HEADER_NAME + " header was present on the request, bypassing " + "leader redirection."); chain.doFilter(request, response); return; } LeaderStatus leaderStatus = redirector.getLeaderStatus(); switch (leaderStatus) { case LEADING: chain.doFilter(request, response); return; case NO_LEADER: sendServiceUnavailable(response); return; case NOT_LEADING: Optional<String> leaderRedirect = redirector.getRedirectTarget(request); if (leaderRedirect.isPresent()) { response.setStatus(HttpServletResponse.SC_TEMPORARY_REDIRECT); response.setHeader(HttpHeaders.LOCATION, leaderRedirect.get()); return; } LOG.warn("Got no leader redirect contrary to leader status, treating as if no leader " + "was found."); sendServiceUnavailable(response); return; default: throw new IllegalArgumentException("Encountered unknown LeaderStatus: " + leaderStatus); } } }