| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.catalina.filters; |
| |
| 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; |
| |
| /** |
| * Filter that attempts to force MS WebDAV clients connecting on port 80 to use |
| * a WebDAV client that actually works. Other workarounds that might help |
| * include: |
| * <ul> |
| * <li>Specifying the port, even if it is port 80, when trying to |
| * connect.</li> |
| * <li>Cancelling the first authentication dialog box and then trying to |
| * reconnect.</li> |
| * </ul> |
| * |
| * Generally each different version of the MS client has a different set of |
| * problems. |
| * <p> |
| * TODO: Update this filter to recognise specific MS clients and apply the |
| * appropriate workarounds for that particular client |
| * <p> |
| * As a filter, this is configured in web.xml like any other Filter. You usually |
| * want to map this filter to whatever your WebDAV servlet is mapped to. |
| * <p> |
| * In addition to the issues fixed by this Filter, the following issues have |
| * also been observed that cannot be fixed by this filter. Where possible the |
| * filter will add an message to the logs. |
| * <p> |
| * XP x64 SP2 (MiniRedir Version 3790) |
| * <ul> |
| * <li>Only connects to port 80</li> |
| * <li>Unknown issue means it doesn't work</li> |
| * </ul> |
| */ |
| public class WebdavFixFilter implements Filter { |
| |
| private static final String LOG_MESSAGE_PREAMBLE = |
| "WebdavFixFilter: Detected client problem: "; |
| |
| /* Start string for all versions */ |
| private static final String UA_MINIDIR_START = |
| "Microsoft-WebDAV-MiniRedir"; |
| /* XP 32-bit SP3 */ |
| private static final String UA_MINIDIR_5_1_2600 = |
| "Microsoft-WebDAV-MiniRedir/5.1.2600"; |
| |
| /* XP 64-bit SP2 */ |
| private static final String UA_MINIDIR_5_2_3790 = |
| "Microsoft-WebDAV-MiniRedir/5.2.3790"; |
| |
| @Override |
| public void init(FilterConfig filterConfig) throws ServletException { |
| // NOOP |
| } |
| |
| @Override |
| public void destroy() { |
| // NOOP |
| } |
| |
| /** |
| * Check for the broken MS WebDAV client and if detected issue a re-direct |
| * that hopefully will cause the non-broken client to be used. |
| */ |
| @Override |
| public void doFilter(ServletRequest request, ServletResponse response, |
| FilterChain chain) throws IOException, ServletException { |
| if (!(request instanceof HttpServletRequest) || |
| !(response instanceof HttpServletResponse)) { |
| chain.doFilter(request, response); |
| return; |
| } |
| HttpServletRequest httpRequest = ((HttpServletRequest) request); |
| HttpServletResponse httpResponse = ((HttpServletResponse) response); |
| String ua = httpRequest.getHeader("User-Agent"); |
| |
| if (ua == null || ua.length() == 0 || |
| !ua.startsWith(UA_MINIDIR_START)) { |
| // No UA or starts with non MS value |
| // Hope everything just works... |
| chain.doFilter(request, response); |
| } else if (ua.startsWith(UA_MINIDIR_5_1_2600)) { |
| // XP 32-bit SP3 - needs redirect with explicit port |
| httpResponse.sendRedirect(buildRedirect(httpRequest)); |
| } else if (ua.startsWith(UA_MINIDIR_5_2_3790)) { |
| // XP 64-bit SP2 |
| if (!"".equals(httpRequest.getContextPath())) { |
| log(request, |
| "XP-x64-SP2 clients only work with the root context"); |
| } |
| // Namespace issue maybe |
| // see http://greenbytes.de/tech/webdav/webdav-redirector-list.html |
| log(request, "XP-x64-SP2 is known not to work with WebDAV Servlet"); |
| |
| chain.doFilter(request, response); |
| } else { |
| // Don't know which MS client it is - try the redirect with an |
| // explicit port in the hope that it moves the client to a different |
| // WebDAV implementation that works |
| httpResponse.sendRedirect(buildRedirect(httpRequest)); |
| } |
| } |
| |
| private String buildRedirect(HttpServletRequest request) { |
| StringBuilder location = |
| new StringBuilder(request.getRequestURL().length()); |
| location.append(request.getScheme()); |
| location.append("://"); |
| location.append(request.getServerName()); |
| location.append(':'); |
| // If we include the port, even if it is 80, then MS clients will use |
| // a WebDAV client that works rather than the MiniRedir that has |
| // problems with BASIC authentication |
| location.append(request.getServerPort()); |
| location.append(request.getRequestURI()); |
| return location.toString(); |
| } |
| |
| private void log(ServletRequest request, String msg) { |
| StringBuilder builder = new StringBuilder(LOG_MESSAGE_PREAMBLE); |
| builder.append(msg); |
| request.getServletContext().log(builder.toString()); |
| } |
| } |