/*
* 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.tomee.webservices;
import org.apache.catalina.Wrapper;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.RequestFacade;
import org.apache.openejb.server.cxf.rs.CxfRsHttpListener;
import org.apache.openejb.server.httpd.ServletRequestAdapter;
import org.apache.openejb.server.httpd.ServletResponseAdapter;
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.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class CXFJAXRSFilter implements Filter {
private static final Field REQUEST;
static {
try {
REQUEST = RequestFacade.class.getDeclaredField("request");
} catch (final NoSuchFieldException e) {
throw new IllegalStateException(e);
}
REQUEST.setAccessible(true);
}
private final CxfRsHttpListener delegate;
private final ConcurrentMap<Wrapper, Boolean> mappingByServlet = new ConcurrentHashMap<>();
private final String[] welcomeFiles;
private String mapping;
public CXFJAXRSFilter(final CxfRsHttpListener delegate, final String[] welcomeFiles) {
this.delegate = delegate;
this.welcomeFiles = new String[welcomeFiles.length];
for (int i = 0; i < welcomeFiles.length; i++) {
this.welcomeFiles[i] = '/' + welcomeFiles[i];
}
}
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
mapping = filterConfig.getInitParameter("mapping");
}
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
if (!HttpServletRequest.class.isInstance(request)) {
chain.doFilter(request, response);
return;
}
final HttpServletRequest httpServletRequest = HttpServletRequest.class.cast(request);
final HttpServletResponse httpServletResponse = HttpServletResponse.class.cast(response);
if (CxfRsHttpListener.TRY_STATIC_RESOURCES) { // else 100% JAXRS
if (servletMappingIsUnderRestPath(httpServletRequest)) {
chain.doFilter(request, response);
return;
}
final InputStream staticContent = delegate.findStaticContent(httpServletRequest, welcomeFiles);
if (staticContent != null) {
chain.doFilter(request, response);
return;
}
}
try {
delegate.doInvoke(
new ServletRequestAdapter(httpServletRequest, httpServletResponse, request.getServletContext()),
new ServletResponseAdapter(httpServletResponse));
} catch (final Exception e) {
throw new ServletException("Error processing webservice request", e);
}
}
private boolean servletMappingIsUnderRestPath(final HttpServletRequest request) {
final HttpServletRequest unwrapped = unwrap(request);
if (!RequestFacade.class.isInstance(unwrapped)) {
return false;
}
final Request tr;
try {
tr = Request.class.cast(REQUEST.get(unwrapped));
} catch (final IllegalAccessException e) {
return false;
}
final Wrapper wrapper = tr.getWrapper();
if (wrapper == null || mapping == null) {
return false;
}
Boolean accept = mappingByServlet.get(wrapper);
if (accept == null) {
accept = false;
if (!"org.apache.catalina.servlets.DefaultServlet".equals(wrapper.getServletClass())) {
for (final String mapping : wrapper.findMappings()) {
if (!mapping.isEmpty() && !"/*".equals(mapping) && !"/".equals(mapping) && !mapping.startsWith("*")
&& mapping.startsWith(this.mapping)) {
accept = true;
break;
}
}
} // else will be handed by getResourceAsStream()
mappingByServlet.putIfAbsent(wrapper, accept);
return accept;
}
return accept;
}
private HttpServletRequest unwrap(final HttpServletRequest request) {
HttpServletRequest unwrapped = request;
boolean changed;
do {
changed = false;
while (HttpServletRequestWrapper.class.isInstance(unwrapped)) {
final HttpServletRequest tmp = HttpServletRequest.class.cast(HttpServletRequestWrapper.class.cast(unwrapped).getRequest());
if (tmp != unwrapped) {
unwrapped = tmp;
} else {
changed = false; // quit
break;
}
changed = true;
}
while (ServletRequestAdapter.class.isInstance(unwrapped)) {
unwrapped = ServletRequestAdapter.class.cast(unwrapped).getRequest();
changed = true;
}
} while (changed);
return unwrapped;
}
@Override
public void destroy() {
// no-op
}
}