io.airlift.http.server.ClassPathResourceHandler.java Source code

Java tutorial

Introduction

Here is the source code for io.airlift.http.server.ClassPathResourceHandler.java

Source

/**
 * Copyright (C) 2012 Ness Computing, Inc.
 *
 * 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 io.airlift.http.server;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteStreams;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.io.WriterOutputStream;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;

import javax.annotation.Nullable;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.List;

/**
 * Serves files from a given folder on the classpath through jetty.
 * Intended to serve a couple of static files e.g. for javascript or HTML.
 */
// Forked from https://github.com/NessComputing/components-ness-httpserver/
public class ClassPathResourceHandler extends AbstractHandler {
    private static final MimeTypes MIME_TYPES;

    static {
        MIME_TYPES = new MimeTypes();
        // Now here is an oversight... =:-O
        MIME_TYPES.addMimeMapping("json", "application/json");
    }

    private final String baseUri;
    private final String classPathResourceBase;
    private final List<String> welcomeFiles;

    public ClassPathResourceHandler(String baseUri, String classPathResourceBase, String... welcomeFiles) {
        this(baseUri, classPathResourceBase, ImmutableList.copyOf(welcomeFiles));
    }

    public ClassPathResourceHandler(String baseUri, String classPathResourceBase, List<String> welcomeFiles) {
        Preconditions.checkNotNull(baseUri, "baseUri is null");
        Preconditions.checkNotNull(classPathResourceBase, "classPathResourceBase is null");
        Preconditions.checkNotNull(welcomeFiles, "welcomeFiles is null");

        baseUri = baseUri.startsWith("/") ? baseUri : '/' + baseUri;
        baseUri = baseUri.endsWith("/") ? baseUri.substring(baseUri.length() - 1) : baseUri;
        this.baseUri = baseUri;

        this.classPathResourceBase = classPathResourceBase;

        ImmutableList.Builder<String> files = ImmutableList.builder();
        for (String welcomeFile : welcomeFiles) {
            if (!welcomeFile.startsWith("/")) {
                welcomeFile = "/" + welcomeFile;
            }
            files.add(welcomeFile);
        }
        this.welcomeFiles = files.build();
    }

    @Override
    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        if (baseRequest.isHandled()) {
            return;
        }

        URL resource = getResourcePath(request);
        if (resource == null) {
            return;
        }

        // When a request hits this handler, it will serve something. Either data or an error.
        baseRequest.setHandled(true);

        String method = request.getMethod();
        boolean skipContent = false;
        if (!HttpMethod.GET.is(method)) {
            if (HttpMethod.HEAD.is(method)) {
                skipContent = true;
            } else {
                response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
                return;
            }
        }

        InputStream resourceStream = null;
        try {
            resourceStream = resource.openStream();

            String contentType = MIME_TYPES.getMimeByExtension(resource.toString());
            response.setContentType(contentType);

            if (skipContent) {
                return;
            }

            // Send the content out. Lifted straight out of ResourceHandler.java
            OutputStream out;
            try {
                out = response.getOutputStream();
            } catch (IllegalStateException e) {
                out = new WriterOutputStream(response.getWriter());
            }

            ByteStreams.copy(resourceStream, out);
        } finally {
            closeQuietly(resourceStream);
        }
    }

    private URL getResourcePath(HttpServletRequest request) {
        String pathInfo = request.getPathInfo();

        // Only serve the content if the request matches the base path.
        if (pathInfo == null || !pathInfo.startsWith(baseUri)) {
            return null;
        }

        // chop off the base uri
        if (!baseUri.equals("/")) {
            pathInfo = pathInfo.substring(baseUri.length());
        }

        if (!pathInfo.startsWith("/") && !pathInfo.isEmpty()) {
            // basepath is /foo and request went to /foobar --> pathInfo starts with bar
            // basepath is /foo and request went to /foo --> pathInfo should be /index.html
            return null;
        }

        // add missing leading slash
        if (!pathInfo.startsWith("/")) {
            pathInfo = "/";
        }

        if (!"/".equals(pathInfo)) {
            String resourcePath = classPathResourceBase + pathInfo;
            URL resource = getClass().getClassLoader().getResource(resourcePath);
            return resource;
        }

        // check welcome files
        for (String welcomeFile : welcomeFiles) {
            String resourcePath = classPathResourceBase + welcomeFile;
            URL resource = getClass().getClassLoader().getResource(resourcePath);
            if (resource != null) {
                return resource;
            }
        }
        return null;
    }

    private static void closeQuietly(@Nullable InputStream in) {
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                // ignored
            }
        }
    }
}