ServletExtension.java

  1. /*
  2.  * Licensed under the Apache License, Version 2.0 (the "License");
  3.  * you may not use this file except in compliance with the License.
  4.  * You may obtain a copy of the License at
  5.  *
  6.  * http://www.apache.org/licenses/LICENSE-2.0
  7.  *
  8.  * Unless required by applicable law or agreed to in writing, software
  9.  * distributed under the License is distributed on an "AS IS" BASIS,
  10.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11.  * See the License for the specific language governing permissions and
  12.  * limitations under the License.
  13.  *
  14.  */

  15. package org.esigate.servlet;

  16. import java.io.IOException;
  17. import java.util.Properties;

  18. import javax.servlet.ServletContext;
  19. import javax.servlet.ServletException;

  20. import org.apache.http.HttpStatus;
  21. import org.apache.http.client.methods.CloseableHttpResponse;
  22. import org.esigate.ConfigurationException;
  23. import org.esigate.Driver;
  24. import org.esigate.HttpErrorPage;
  25. import org.esigate.Parameters;
  26. import org.esigate.api.ContainerRequestContext;
  27. import org.esigate.events.Event;
  28. import org.esigate.events.EventDefinition;
  29. import org.esigate.events.EventManager;
  30. import org.esigate.events.IEventListener;
  31. import org.esigate.events.impl.FetchEvent;
  32. import org.esigate.extension.Extension;
  33. import org.esigate.http.IncomingRequest;
  34. import org.esigate.http.OutgoingRequest;
  35. import org.esigate.http.OutgoingRequestContext;
  36. import org.esigate.servlet.impl.ResponseCapturingWrapper;
  37. import org.esigate.servlet.impl.ResponseSender;
  38. import org.esigate.util.UriUtils;

  39. /**
  40.  * Extension to enable local or cross-context includes inside a J2EE web application.
  41.  *
  42.  * This extension does not support background revalidation as it is not compliant with the Servlet request lifecycle.
  43.  *
  44.  * @author Francois-Xavier Bonnet
  45.  *
  46.  */
  47. public class ServletExtension implements Extension, IEventListener {
  48.     private Driver driver;
  49.     private String context;
  50.     private int maxObjectSize;
  51.     private final ResponseSender responseSender = new ResponseSender();

  52.     @Override
  53.     public void init(Driver driverParam, Properties properties) {
  54.         this.driver = driverParam;
  55.         driverParam.getEventManager().register(EventManager.EVENT_FETCH_PRE, this);
  56.         context = properties.getProperty("context");
  57.         maxObjectSize = Parameters.MAX_OBJECT_SIZE.getValue(properties);
  58.         if (!Parameters.STALE_WHILE_REVALIDATE.getDefaultValue().equals(
  59.                 Parameters.STALE_WHILE_REVALIDATE.getValue(properties))) {
  60.             throw new ConfigurationException("ServletExtension does not support background revalidation ("
  61.                     + driver.getConfiguration().getInstanceName() + ".staleWhileRevalidate="
  62.                     + Parameters.STALE_WHILE_REVALIDATE.getValue(properties) + ")");
  63.         }
  64.     }

  65.     @Override
  66.     public boolean event(EventDefinition id, Event event) {
  67.         FetchEvent fetchEvent = (FetchEvent) event;
  68.         if (EventManager.EVENT_FETCH_PRE.equals(id)) {
  69.             String uriString = fetchEvent.getHttpRequest().getRequestLine().getUri();
  70.             OutgoingRequest outgoingRequest =
  71.                     OutgoingRequestContext.adapt(fetchEvent.getHttpContext()).getOutgoingRequest();
  72.             IncomingRequest incomingRequest = outgoingRequest.getOriginalRequest().getOriginalRequest();
  73.             String baseUrl = outgoingRequest.getBaseUrl().toString();
  74.             if (outgoingRequest.getOriginalRequest().isExternal()) {
  75.                 // Non local absolute uri
  76.                 return true;
  77.             } else {
  78.                 String relUrl = uriString;
  79.                 if (UriUtils.isAbsolute(relUrl)) {
  80.                     relUrl = relUrl.substring(UriUtils.extractHost(relUrl).toURI().length());
  81.                 }
  82.                 relUrl = relUrl.substring(UriUtils.getPath(baseUrl).length());
  83.                 if (!relUrl.startsWith("/")) {
  84.                     relUrl = "/" + relUrl;
  85.                 }
  86.                 ContainerRequestContext requestContext = outgoingRequest.getContainerRequestContext();
  87.                 CloseableHttpResponse result;
  88.                 if (!(requestContext instanceof HttpServletRequestContext)) {
  89.                     String message =
  90.                             ServletExtension.class.getName() + " can be used only inside a java servlet engine";
  91.                     result = HttpErrorPage.generateHttpResponse(HttpStatus.SC_BAD_GATEWAY, message);
  92.                 } else {
  93.                     HttpServletRequestContext httpServletRequestContext = (HttpServletRequestContext) requestContext;
  94.                     try {
  95.                         if (fetchEvent.getHttpContext().isProxy()) {
  96.                             ResponseCapturingWrapper wrappedResponse =
  97.                                     new ResponseCapturingWrapper(httpServletRequestContext.getResponse(),
  98.                                             driver.getContentTypeHelper(), true, maxObjectSize, responseSender,
  99.                                             incomingRequest);
  100.                             if (context == null) {
  101.                                 httpServletRequestContext.getFilterChain().doFilter(
  102.                                         httpServletRequestContext.getRequest(), wrappedResponse);
  103.                                 result = wrappedResponse.getCloseableHttpResponse();
  104.                             } else {
  105.                                 ServletContext crossContext =
  106.                                         httpServletRequestContext.getServletContext().getContext(context);
  107.                                 if (crossContext == null) {
  108.                                     String message = "Context " + context + " does not exist or cross context disabled";
  109.                                     result = HttpErrorPage.generateHttpResponse(HttpStatus.SC_BAD_GATEWAY, message);
  110.                                 } else {
  111.                                     crossContext.getRequestDispatcher(relUrl).forward(
  112.                                             httpServletRequestContext.getRequest(), wrappedResponse);
  113.                                     result = wrappedResponse.getCloseableHttpResponse();
  114.                                 }
  115.                             }
  116.                         } else {
  117.                             ResponseCapturingWrapper wrappedResponse =
  118.                                     new ResponseCapturingWrapper(httpServletRequestContext.getResponse(),
  119.                                             driver.getContentTypeHelper(), false, maxObjectSize, responseSender,
  120.                                             incomingRequest);
  121.                             if (context == null) {
  122.                                 httpServletRequestContext.getRequest().getRequestDispatcher(relUrl)
  123.                                         .forward(httpServletRequestContext.getRequest(), wrappedResponse);
  124.                                 result = wrappedResponse.getCloseableHttpResponse();
  125.                             } else {
  126.                                 ServletContext crossContext =
  127.                                         httpServletRequestContext.getServletContext().getContext(context);
  128.                                 if (crossContext == null) {
  129.                                     String message = "Context " + context + " does not exist or cross context disabled";
  130.                                     result = HttpErrorPage.generateHttpResponse(HttpStatus.SC_BAD_GATEWAY, message);
  131.                                 } else {
  132.                                     crossContext.getRequestDispatcher(relUrl).include(
  133.                                             httpServletRequestContext.getRequest(), wrappedResponse);
  134.                                     result = wrappedResponse.getCloseableHttpResponse();
  135.                                 }
  136.                             }
  137.                         }
  138.                     } catch (IOException | ServletException e) {
  139.                         result = HttpErrorPage.generateHttpResponse(e);
  140.                     }
  141.                 }
  142.                 fetchEvent.setHttpResponse(result);
  143.                 // Stop execution
  144.                 fetchEvent.setExit(true);
  145.             }
  146.         }
  147.         return true;
  148.     }
  149. }