blob: 7cddc31f72bdac5306a6bbb4fcd5630db456b582 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2018, 2020 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.rhelp.core.http.jetty;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.CompressedContentFormat;
import org.eclipse.jetty.http.HttpContent;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.PreEncodedHttpField;
import org.eclipse.jetty.server.ResourceContentFactory;
import org.eclipse.jetty.server.ResourceService;
import org.eclipse.jetty.util.resource.PathResource;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.rhelp.core.http.MimeTypes;
import org.eclipse.statet.rhelp.core.http.ResourceHandler;
@NonNullByDefault
public class JettyResourceHandler extends ResourceService implements ResourceHandler, ResourceFactory {
private static class JettyMimeTypes extends org.eclipse.jetty.http.MimeTypes {
private final MimeTypes defaultTypes;
private @Nullable MimeTypes specialTypes;
public JettyMimeTypes(final MimeTypes mimeTypes) {
this.defaultTypes= mimeTypes;
}
@Override
public @Nullable String getMimeByExtension(String filename) {
final int idx= Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
if (idx >= 0) {
filename= filename.substring(idx + 1);
}
String type= null;
if (this.specialTypes != null) {
type= this.specialTypes.getMimeType(filename);
}
if (type == null) {
type= this.defaultTypes.getMimeType(filename);
}
if (type == null) {
type= super.getMimeByExtension(filename);
}
return type;
}
}
private final JettyMimeTypes mimeTypes;
public JettyResourceHandler(final MimeTypes defaultTypes) {
this.mimeTypes= new JettyMimeTypes(defaultTypes);
setContentFactory(new ResourceContentFactory(this, this.mimeTypes,
new CompressedContentFormat[0] ));
}
@Override
public void setSpecialMimeTypes(final MimeTypes types) {
this.mimeTypes.specialTypes= types;
}
@Override
public void setCacheControl(final String value) {
setCacheControl(new PreEncodedHttpField(HttpHeader.CACHE_CONTROL, value));
}
@Override
public Resource getResource(final String path) {
return new PathResource(Paths.get(path));
}
@Override
public void doGet(final Path path,
final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
final HttpContent content= getContentFactory().getContent(path.toString(), resp.getBufferSize());
boolean releaseContent= true;
try {
if (content == null || !content.getResource().exists()) {
notFound(req, resp);
return;
}
if (content.getResource().isDirectory()) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
}
if (!passConditionalHeaders(req, resp, content)) {
return;
}
Enumeration<String> reqRanges= req.getHeaders(HttpHeader.RANGE.asString());
if (reqRanges != null && !reqRanges.hasMoreElements()) {
reqRanges= null;
}
releaseContent= sendData(req, resp, false, content, reqRanges);
}
finally {
if (releaseContent && content != null) {
content.release();
}
}
}
}