All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.finos.legend.server.shared.localassets.LocalAssetServlet Maven / Gradle / Ivy

// Copyright 2020 Goldman Sachs
//
// Licensed 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.finos.legend.server.shared.localassets;

import com.google.common.base.Strings;
import com.google.common.io.ByteStreams;
import io.dropwizard.servlets.assets.AssetServlet;
import io.dropwizard.servlets.assets.ResourceURL;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Optional;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;

public class LocalAssetServlet extends AssetServlet
{

  private final Map localPaths;
  private final String resourcePath;

  /**
   * Creates a new {@code AssetServlet} that serves static assets loaded from {@code resourceURL}
   * (typically a file: or jar: URL). The assets are served at URIs rooted at {@code uriPath}. For
   * example, given a {@code resourceURL} of {@code "file:/data/assets"} and a {@code uriPath} of
   * {@code "/js"}, an {@code AssetServlet} would serve the contents of {@code
   * /data/assets/example.js} in response to a request for {@code /js/example.js}. If a directory is
   * requested and {@code indexFile} is defined, then {@code AssetServlet} will attempt to serve a
   * file with that name in that directory. If a directory is requested and {@code indexFile} is
   * null, it will serve a 404.
   *
   * @param localPaths     the base URL from which assets are loaded
   * @param uriPath        the URI path fragment in which all requests are rooted
   * @param indexFile      the filename to use when dirs are requested, or null to serve no indexes
   * @param defaultCharset the default character set
   */
  public LocalAssetServlet(Map localPaths, String resourcePath, String uriPath,
                           String indexFile, Charset defaultCharset)
  {
    super("/", uriPath, indexFile, defaultCharset);
    this.localPaths = localPaths;
    this.resourcePath = resourcePath;
  }

  private boolean shouldCacheContentType(String contentType)
  {
    boolean shouldCache = true;
    if (contentType != null && contentType.startsWith(MediaType.TEXT_HTML))
    {
      shouldCache = false;
    }
    if (contentType != null && contentType.startsWith(MediaType.APPLICATION_JSON))
    {
      shouldCache = false;
    }
    return shouldCache;
  }

  private String getPath(HttpServletRequest req)
  {
    final StringBuilder builder = new StringBuilder(req.getServletPath());
    if (req.getPathInfo() != null)
    {
      builder.append(req.getPathInfo());
    }
    return builder.toString();
  }


  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException
  {
    final String absoluteRequestedResourcePath = getPath(req);
    try
    {
      URL requestedResourceUrl = getResourceUrl(absoluteRequestedResourcePath);
      try
      {
        if (ResourceURL.isDirectory(requestedResourceUrl) && !absoluteRequestedResourcePath
            .endsWith("/"))
        {
          resp.sendRedirect(absoluteRequestedResourcePath + "/");
          req = new HttpServletRequestWrapper(req)
          {
            @Override
            public String getPathInfo()
            {
              String path = super.getPathInfo();
              return path != null ? path + "/" : "/";
            }
          };
        }
      } catch (URISyntaxException e)
      {
        throw new IOException(e);
      }

      resp = new HttpServletResponseWrapper(resp)
      {
        @Override
        public void setContentType(String contentType)
        {
          super.setContentType(contentType);
          if (!shouldCacheContentType(contentType))
          {
            CacheControl cacheControl = new CacheControl();
            cacheControl.setMustRevalidate(true);
            cacheControl.setNoCache(true);
            this.addHeader(HttpHeaders.CACHE_CONTROL, cacheControl.toString());
          }
        }
      };

      super.doGet(req, resp);
    } catch (FileNotFoundException | IllegalArgumentException e)
    {
      resp.sendError(HttpServletResponse.SC_NOT_FOUND,
          "Unable to find " + absoluteRequestedResourcePath);
    }
  }

  @Override
  protected URL getResourceUrl(String requestedResourcePath)
  {
    final String absoluteRequestedResourcePath =
        requestedResourcePath.startsWith("/") ? requestedResourcePath : "/" + requestedResourcePath;
    Optional matchingPath = localPaths.keySet().stream()
        .filter(absoluteRequestedResourcePath::startsWith).findFirst();
    if (matchingPath.isPresent())
    {
      try
      {
        return new URL("file:///" + localPaths.get(matchingPath.get()).replace('\\', '/')
            + (absoluteRequestedResourcePath).replace(matchingPath.get(), "/"));
      } catch (MalformedURLException e)
      {
        throw new RuntimeException(e);
      }
    } else if (Strings.isNullOrEmpty(this.resourcePath))
    {
      return super.getResourceUrl(absoluteRequestedResourcePath.substring(1));
    } else
    {
      return super.getResourceUrl(this.resourcePath + absoluteRequestedResourcePath);
    }
  }

  @Override
  protected byte[] readResource(URL requestedResourceUrl) throws IOException
  {
    if (requestedResourceUrl.getProtocol().equals("file"))
    {
      try (InputStream stream = requestedResourceUrl.openStream())
      {
        return ByteStreams.toByteArray(stream);
      }
    }
    return super.readResource(requestedResourceUrl);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy