// Copyright (C) 2009 The Android Open Source Project // // 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 com.google.gerrit.httpd; import com.google.gerrit.common.Nullable; import com.google.gerrit.server.config.CanonicalWebUrl; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.inject.servlet.ServletModule; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** Requires the connection to use SSL, redirects if not. */ @Singleton class RequireSslFilter implements Filter { static class Module extends ServletModule { @Override protected void configureServlets() { filter("/*").through(RequireSslFilter.class); } } private final Provider<String> urlProvider; @Inject RequireSslFilter(@CanonicalWebUrl @Nullable final Provider<String> urlProvider) { this.urlProvider = urlProvider; } @Override public void init(FilterConfig filterConfig) { } @Override public void destroy() { } @Override public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { final HttpServletRequest req = (HttpServletRequest) request; final HttpServletResponse rsp = (HttpServletResponse) response; if (isSecure(req)) { chain.doFilter(request, response); } else { // If we wanted SSL, but the user didn't come to us over it, // force SSL by issuing a protocol redirect. Try to keep the // name "localhost" in case this is an SSH port tunnel. // final String url; if (isLocalHost(req)) { final StringBuffer b = req.getRequestURL(); b.replace(0, b.indexOf(":"), "https"); url = b.toString(); } else { url = urlProvider.get() + req.getServletPath(); } rsp.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); rsp.setHeader("Location", url); } } private static boolean isSecure(final HttpServletRequest req) { return "https".equals(req.getScheme()) || req.isSecure(); } private static boolean isLocalHost(final HttpServletRequest req) { return "localhost".equals(req.getServerName()) || "127.0.0.1".equals(req.getServerName()); } }