| /*=============================================================================# |
| # 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.MediaTypeProvider; |
| 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 MediaTypeProvider defaultMediaTypes; |
| |
| private @Nullable MediaTypeProvider specialMediaTypes; |
| |
| |
| public JettyMimeTypes(final MediaTypeProvider mimeTypes) { |
| this.defaultMediaTypes= 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.specialMediaTypes != null) { |
| type= this.specialMediaTypes.getMediaTypeString(filename); |
| } |
| if (type == null) { |
| type= this.defaultMediaTypes.getMediaTypeString(filename); |
| } |
| if (type == null) { |
| type= super.getMimeByExtension(filename); |
| } |
| return type; |
| } |
| |
| } |
| |
| |
| private final JettyMimeTypes mediaTypes; |
| |
| |
| public JettyResourceHandler(final MediaTypeProvider defaultTypes) { |
| this.mediaTypes= new JettyMimeTypes(defaultTypes); |
| setContentFactory(new ResourceContentFactory(this, this.mediaTypes, |
| new CompressedContentFormat[0] )); |
| } |
| |
| |
| @Override |
| public void setSpecialMediaTypes(final MediaTypeProvider types) { |
| this.mediaTypes.specialMediaTypes= 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(); |
| } |
| } |
| } |
| |
| } |