package at.ac.ait.archistar.engine.userinterface; import java.net.URI; import java.net.URISyntaxException; import java.util.LinkedList; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.PreMatching; import javax.ws.rs.ext.Provider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * this filter should normalize incoming requests. S3 allows two ways of * addressing incoming requests: path style and virtual style. With this filter * all requests should be normalized to using a virtual style request * * @author Andreas Happe <andreashappe@snikt.net> */ @Provider @PreMatching public class RedirectorFilter implements ContainerRequestFilter { private final Logger logger = LoggerFactory.getLogger(RedirectorFilter.class); @Override public void filter(ContainerRequestContext requestContext) { /* Host header: for path style this should be s3.amazonaws.com, * for virtual-style this should be <bucket>.s3.amazonaws.com */ String host = requestContext.getHeaderString("Host"); if (host.endsWith(".s3.amazonaws.com")) { /* bucket name is already set, do nothing */ } else { /* this is some invalid host -- normally this means this is a * local S3 installation -- try to extract the bucket from * the path and set it as header */ adoptBucket(requestContext); } } private void adoptBucket(ContainerRequestContext ctx) { /* extract bucket */ URI uri = ctx.getUriInfo().getRequestUri(); String path = uri.getPath(); String bucketString = ""; String bucket = ""; String query = uri.getQuery(); logger.debug("Input: " + uri.toString()); if (path.equals("/")) { bucketString = "s3.amazonaws.com"; path = "/"; } else { Pattern p = Pattern.compile("^/*([^/]+)(.*)$"); Matcher m = p.matcher(path); if (m.find() && m.groupCount() == 2) { bucket = m.group(1); path = m.group(2); bucketString = bucket.concat(".s3.amazonaws.com"); } else { throw new RuntimeException(); } } /* nothing found, try query params */ if (path != null && uri.getQuery() != null && bucket.equalsIgnoreCase("") && path.equalsIgnoreCase("/") && !uri.getQuery().isEmpty()) { StringBuilder buffer = new StringBuilder(); for (String part : uri.getQuery().split("&")) { if (buffer.length() != 0) { buffer.append("&"); } String key = part.split("=")[0]; String value = part.split("=")[1]; if (key.equalsIgnoreCase("prefix")) { Pattern p = Pattern.compile("^/*([^/]+)(.*)$"); Matcher m = p.matcher(value); if (m.find()) { bucket = m.group(1); bucketString = bucket + ".s3.amazonaws.com"; buffer.append("prefix="); buffer.append(m.group(2)); } else { buffer.append(part); } } else { buffer.append(part); } } query = buffer.toString(); } logger.debug("redirected: " + uri.toString() + " -> " + bucket + "/" + path + "?" + query); /* set Bucket */ ctx.getHeaders().add("X-Bucket", bucket); /* set Host */ LinkedList<String> list = new LinkedList<>(); list.add(bucketString); ctx.getHeaders().put("Host", list); /* set URI */ try { URI target = new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), path, query, uri.getFragment()); logger.info("redirected: " + uri.toString() + " -> " + target.toString()); ctx.setRequestUri(target); } catch (URISyntaxException e) { assert(false); } } }