001/* 002 * (C) Copyright 2006-2012 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nuxeo - initial API and implementation 016 * 017 */ 018 019package org.nuxeo.ecm.platform.ui.web.rest; 020 021import java.io.IOException; 022 023import javax.servlet.Filter; 024import javax.servlet.FilterChain; 025import javax.servlet.FilterConfig; 026import javax.servlet.RequestDispatcher; 027import javax.servlet.ServletContext; 028import javax.servlet.ServletException; 029import javax.servlet.ServletRequest; 030import javax.servlet.ServletResponse; 031import javax.servlet.http.HttpServletRequest; 032import javax.servlet.http.HttpServletResponse; 033 034import org.apache.commons.logging.Log; 035import org.apache.commons.logging.LogFactory; 036import org.nuxeo.ecm.core.io.download.DownloadHelper; 037import org.nuxeo.ecm.platform.ui.web.rest.api.URLPolicyService; 038import org.nuxeo.ecm.platform.url.api.DocumentView; 039import org.nuxeo.runtime.api.Framework; 040 041/** 042 * Filter used to decode URLs and wrap requests to enable encoding. This filter is useful because Nuxeo support 043 * pluggable URL patterns 044 * 045 * @author tiry 046 */ 047public class FancyURLFilter implements Filter { 048 049 private static final Log log = LogFactory.getLog(FancyURLFilter.class); 050 051 protected URLPolicyService urlService; 052 053 protected ServletContext servletContext; 054 055 @Override 056 public void init(FilterConfig conf) throws ServletException { 057 log.debug("Nuxeo5 URLFilter started"); 058 servletContext = conf.getServletContext(); 059 } 060 061 protected URLPolicyService getUrlService() { 062 if (urlService == null) { 063 urlService = Framework.getService(URLPolicyService.class); 064 } 065 return urlService; 066 } 067 068 @Override 069 public void destroy() { 070 urlService = null; 071 } 072 073 @Override 074 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, 075 ServletException { 076 HttpServletRequest httpRequest = (HttpServletRequest) request; 077 HttpServletResponse httpResponse = (HttpServletResponse) response; 078 try { 079 getUrlService(); 080 // initialize its view id manager if necessary 081 urlService.initViewIdManager(servletContext, httpRequest, httpResponse); 082 083 // check if this is an URL that needs to be parsed 084 if (urlService.isCandidateForDecoding(httpRequest)) { 085 DocumentView docView = urlService.getDocumentViewFromRequest(httpRequest); 086 // if parse succeeded => process 087 if (docView != null) { 088 // put it in request 089 urlService.setDocumentViewInRequest(httpRequest, docView); 090 091 // get the view id for navigation from the stored outcome 092 String jsfOutcome = docView.getViewId(); 093 094 // get target page according to navigation rules 095 String target = urlService.getViewIdFromOutcome(jsfOutcome, httpRequest); 096 097 // dispatch 098 RequestDispatcher dispatcher; 099 if (target != null) { 100 dispatcher = httpRequest.getRequestDispatcher(target); 101 } else { 102 // Use a dummy dispatcher if the target is not needed. 103 // This comes handy for instance for nxfile url 104 dispatcher = httpRequest.getRequestDispatcher("/malformed_url_error_page.faces"); 105 } 106 // set force encoding in case forward triggers a 107 // redirect (when a seam page is processed for instance). 108 request.setAttribute(URLPolicyService.FORCE_URL_ENCODING_REQUEST_KEY, Boolean.TRUE); 109 // forward request to the target viewId 110 dispatcher.forward(new FancyURLRequestWrapper(httpRequest, docView), 111 wrapResponse(httpRequest, httpResponse)); 112 return; 113 } 114 } 115 116 // do not filter if it's candidate for encoding so soon : document 117 // view has not been set in the request yet => always wrap 118 chain.doFilter(request, wrapResponse(httpRequest, httpResponse)); 119 120 } catch (IOException e) { 121 String url = httpRequest.getRequestURL().toString(); 122 if (DownloadHelper.isClientAbortError(e)) { 123 DownloadHelper.logClientAbort(e); 124 log.debug(String.format("Client disconnected from URL %s : %s", url, e.getMessage())); 125 } else { 126 throw new IOException("On requestURL: " + url, e); 127 } 128 } catch (ServletException e) { 129 String url = httpRequest.getRequestURL().toString(); 130 if (DownloadHelper.isClientAbortError(e)) { 131 DownloadHelper.logClientAbort(e); 132 log.debug(String.format("Client disconnected from URL %s : %s", url, e.getMessage())); 133 } else { 134 throw new ServletException("On requestURL: " + url, e); 135 } 136 } 137 138 } 139 140 protected ServletResponse wrapResponse(HttpServletRequest request, HttpServletResponse response) { 141 return new FancyURLResponseWrapper(response, request); 142 } 143 144}