/*
* Copyright © 2014 Cask Data, 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 co.cask.cdap.internal.app.runtime.webapp;
import co.cask.cdap.common.conf.Constants;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import java.net.URI;
/**
* Determines the path to serve based on the Host header.
*/
public class ServePathGenerator {
public static final String SRC_PATH = "/src/";
public static final String DEFAULT_DIR_NAME = "default";
private static final String GATEWAY_PATH_V3 = Constants.Gateway.API_VERSION_3.substring(1) + "/";
private static final String DEFAULT_PORT_STR = ":80";
private final String baseDir;
private final Predicate<String> fileExists;
public ServePathGenerator(String baseDir, Predicate<String> fileExists) {
this.baseDir = baseDir.replaceAll("/+$", "");
this.fileExists = fileExists;
}
public String getServePath(String hostHeader, String uriString) {
URI uri = URI.create(uriString);
String path = uri.getPath();
String query = uri.getQuery();
if (path.startsWith("/")) {
path = path.substring(1);
}
if (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
// If exact match present, return it
String servePath = findPath(hostHeader, path, query);
if (servePath != null) {
return constructURI(servePath);
}
boolean isDefaultPort = hostHeader.endsWith(DEFAULT_PORT_STR);
boolean hasNoPort = hostHeader.indexOf(':') == -1;
// Strip DEFAULT_PORT_STR and try again
if (isDefaultPort) {
servePath = findPath(hostHeader.substring(0, hostHeader.length() - DEFAULT_PORT_STR.length()), path, query);
if (servePath != null) {
return constructURI(servePath);
}
}
// Add DEFAULT_PORT_STR and try
if (hasNoPort) {
servePath = findPath(hostHeader + DEFAULT_PORT_STR, path, query);
if (servePath != null) {
return constructURI(servePath);
}
}
// Else if "default" is present, that is the serve dir
servePath = findPath(DEFAULT_DIR_NAME, path, query);
if (servePath != null) {
return constructURI(servePath);
}
return constructURI(path);
}
private String constructURI(String servePath) {
return servePath.startsWith("/") ? servePath : "/" + servePath;
}
private String findPath(String hostHeader, String path, String query) {
// First try firstPathPart/src/restPath
Iterable<String> pathParts = Splitter.on('/').limit(2).split(path);
String servePath;
if (Iterables.size(pathParts) > 1) {
String part1 = Iterables.get(pathParts, 1);
if (part1.startsWith(GATEWAY_PATH_V3) || part1.equals("status")) {
return constructPath(part1, query);
}
servePath = String.format("%s/%s/%s%s%s", baseDir, hostHeader,
Iterables.get(pathParts, 0), SRC_PATH, Iterables.get(pathParts, 1));
if (fileExists.apply(servePath)) {
return servePath;
}
} else if (Iterables.size(pathParts) == 1) {
servePath = String.format("%s/%s/%s%s%s", baseDir, hostHeader,
Iterables.get(pathParts, 0), SRC_PATH, "index.html");
if (fileExists.apply(servePath)) {
return servePath;
}
}
// Next try src/path
if (path.startsWith(GATEWAY_PATH_V3) || path.equals("status")) {
return constructPath(path, query);
}
path = path.isEmpty() ? "index.html" : path;
servePath = String.format("%s/%s%s%s", baseDir, hostHeader, SRC_PATH, path);
if (fileExists.apply(servePath)) {
return servePath;
}
return null;
}
private String constructPath(String path, String query) {
return query == null ? path : String.format("%s?%s", path, query);
}
}