Kategorien
java

Wenn der Redirect im Halse stecken bleibt

Gestern haben wir unseren nexus-Server auf den neuesten Stand gebracht und kurz danach funktionierten unsere ant-Skripte zum Herunterladen von Artefakten aus dem nexus nicht mehr. Das Problem war schnell gefunden, die nexus Entwickler haben den Status-Code für einen Redirect von 301 (moved permanently) auf 307 (temporary redirect) geändert. Das ist wohl moderner und kann den Client vom Caching abhalten. Leider haben die ant Entwickler das in ihren alten Versionen, die wir einsetzen, noch nicht gewusst und kommen damit nicht klar.

Da der nexus aber in einem Servlet Container läuft, kann man einen Filter einrichten, der alle Redirects mit Status-Code 307 (temporary redirect) auf den alten Wert 302 (moved temporarily) ändert.

Dazu kann der folgende Java-Code genutzt werden:

package de.bytewurf.example;

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.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

/**
 * Servlet Filter implementation class ChangeRedirectFilter
 */
@WebFilter(description = "Changes calls to setStatus with value 307 to 302", urlPatterns = { "/" })
public class ChangeRedirectFilter implements Filter {

	private static class ChangeRedirectWrapper extends
			HttpServletResponseWrapper {

		public ChangeRedirectWrapper(HttpServletResponse response) {
			super(response);
		}

		@Override
		public void setStatus(int sc) {
			if (sc == SC_TEMPORARY_REDIRECT) {
				super.setStatus(SC_MOVED_TEMPORARILY);
			} else {
				super.setStatus(sc);
			}
		}

	}

	/**
	 * @see Filter#destroy()
	 */
	public void destroy() {
	}

	/**
	 * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
	 */
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		if (request instanceof HttpServletRequest
				&& response instanceof HttpServletResponse) {
			HttpServletRequest httpRequest = (HttpServletRequest) request;
			HttpServletResponse httpResponse = (HttpServletResponse) response;
			if (!response.isCommitted()) {
				chain.doFilter(httpRequest, new ChangeRedirectWrapper(
						httpResponse));
				return;
			}
		}
		chain.doFilter(request, response);
	}

	/**
	 * @see Filter#init(FilterConfig)
	 */
	public void init(FilterConfig fConfig) throws ServletException {
		fConfig.getServletContext().log("init ChangedRedirectFilter");
	}

}

Die wichtigsten Komponenten dabei sind zum Einen die Methode doFilter(req, resp) im Filter, die bei jedem Request aufgerufen wird — wenn der Filter richtig eingerichtet ist. Die Methode prüft, ob es sich um eine HTTP Anfrage handelt und noch nicht committed ist, sprich die Header schon zum Client gesendet wurden. Ist beides erfüllt, so wird die Response in einen Wrapper (innere Klasse ChangeRedirectWrapper) gepackt.

Die innere Klasse ChangeRedirectWrapper reicht alle Methodenaufrufe an die eingepackte Response durch, bis auf die setStatus(code) Methode. Hier wird geprüft, ob der Code gleich 307 ist. In diesem Fall wird auf der eingepackten Response setStatus mit dem Wert 302 aufgerufen.

Nachdem dieser Filter eingerichtet war, funktionierte netterweise auch ant wieder und wir haben Zeit ant auf eine neuere Version zu heben.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.