package org.geowebcache.rest.webresources; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.util.List; import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.geowebcache.GeoWebCacheExtensions; import org.geowebcache.mime.MimeException; import org.geowebcache.mime.MimeType; import org.geowebcache.rest.GWCRestlet; import org.geowebcache.rest.RestletException; import org.restlet.data.MediaType; import org.restlet.data.Method; import org.restlet.data.Request; import org.restlet.data.Response; import org.restlet.data.Status; import org.restlet.resource.OutputRepresentation; public class ByteStreamerRestlet extends GWCRestlet { private static Log log = LogFactory.getLog(ByteStreamerRestlet.class); WebResourceBundle bundle; public void handle(Request request, Response response) { Method met = request.getMethod(); if (met.equals(Method.GET)) { doGet(request, response); } else { throw new RestletException("Method not allowed", Status.CLIENT_ERROR_METHOD_NOT_ALLOWED); } } private static final WebResourceBundle DEFAULT_BUNDLE = ByteStreamerRestlet.class::getResource; protected URL getResource(String path) { if(bundle==null) { synchronized(this) { if(bundle==null) { List<WebResourceBundle> result=GeoWebCacheExtensions.extensions(WebResourceBundle.class); if(result.isEmpty()) { bundle = DEFAULT_BUNDLE; } else { bundle = result.get(0); if(result.size()>1) { log.warn("Multiple web resource bundles present, using "+bundle.getClass().getName()); } } } } } URL resource = bundle.apply(path); if(resource==null && bundle != DEFAULT_BUNDLE) { resource = DEFAULT_BUNDLE.apply(path); } return resource; } static final Pattern UNSAFE_RESOURCE = Pattern.compile("^/|/\\.\\./|^\\.\\./|\\.class$"); private void doGet(Request request, Response response) { String filename = (String) request.getAttributes().get("filename"); // Just to make sure we don't allow access to arbitrary resources if(UNSAFE_RESOURCE.matcher(filename).find()) { throw new RestletException("Illegal web resource", Status.CLIENT_ERROR_FORBIDDEN); } URL resource = getResource(filename); if(resource == null) { response.setStatus(Status.CLIENT_ERROR_NOT_FOUND); return; } response.setStatus(Status.SUCCESS_OK); String[] filenameParts = filename.split("\\."); String extension = filenameParts[filenameParts.length - 1]; MimeType mime = null; try { mime = MimeType.createFromExtension(extension); } catch (MimeException e) { response.setStatus(Status.SERVER_ERROR_INTERNAL); response.setEntity("Unable to create MimeType for " + extension); return; } ByteRepresentation imgRep = new ByteRepresentation(new MediaType(mime.getMimeType()), resource); response.setEntity(imgRep); } private class ByteRepresentation extends OutputRepresentation { URL resourceURL; public ByteRepresentation(MediaType mediaType, URL resourceURL) { super(mediaType); this.resourceURL = resourceURL; } public void write(OutputStream os) throws IOException { try( InputStream is = resourceURL.openStream(); ){ int count = 0; byte[] tmp = new byte[2048]; while(count != -1) { count = is.read(tmp); if(count != -1) { os.write(tmp, 0, count); } } } } } }