package com.hp.autonomy.frontend.find.core.map;
import com.hp.autonomy.frontend.configuration.ConfigService;
import com.hp.autonomy.frontend.find.core.configuration.FindConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.regex.Pattern;
@Slf4j
@Controller
@RequestMapping(MapController.MAP_PATH)
class MapController {
static final String MAP_PATH = "/api/public/map";
private static final String PROXY_PATH = "/proxy";
private static final String URL_PARAM = "url";
private static final String CALLBACK_PARAM = "callback";
private static final Pattern CALLBACK_FUNCTION_NAME_PATTERN = Pattern.compile("\\w+");
private final ConfigService<? extends FindConfig<?, ?>> configService;
@Autowired
MapController(@SuppressWarnings("SpringJavaAutowiringInspection") final ConfigService<? extends FindConfig<?, ?>> configService) {
this.configService = configService;
}
@SuppressWarnings("OverlyBroadCatchBlock")
@RequestMapping(value = PROXY_PATH, method = RequestMethod.GET)
@ResponseBody
public String getMapData(
@RequestParam(URL_PARAM) final String url,
@RequestParam(CALLBACK_PARAM) final String callback
) {
if (!CALLBACK_FUNCTION_NAME_PATTERN.matcher(callback).matches()) {
throw new IllegalArgumentException("Invalid callback function name");
}
try {
final String tileUrlTemplate = configService.getConfig().getMap().getTileUrlTemplate();
final URL targetURL = new URL(url);
final URL validationURL = new URL(tileUrlTemplate);
if (!validationURL.getProtocol().equals(targetURL.getProtocol()) || !validationURL.getHost().equals(targetURL.getHost()) || validationURL.getPort() != targetURL.getPort()) {
throw new IllegalArgumentException("We only allow proxying to the tile server");
}
final URLConnection urlConnection = targetURL.openConnection();
final String contentType = urlConnection.getContentType();
return getMapData(callback, urlConnection, contentType);
} catch (final IOException e) {
log.error("Error retrieving map data", e);
return callback + "(\"error:Application error\")";
}
}
private String getMapData(final String callback, final URLConnection urlConnection, final String contentType) throws IOException {
try (final InputStream inputStream = urlConnection.getInputStream(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
IOUtils.copyLarge(inputStream, outputStream);
return callback + "(\"data:" + contentType + ";base64," + new String(Base64.encodeBase64(outputStream.toByteArray(), false, false)) + "\")";
}
}
}