package ru.qatools.gridrouter;
import org.apache.commons.io.IOUtils;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import ru.qatools.gridrouter.json.JsonMessage;
import ru.qatools.gridrouter.json.JsonMessageFactory;
import ru.qatools.gridrouter.sessions.StatsCounter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.springframework.web.context.support.SpringBeanAutowiringSupport.processInjectionBasedOnServletContext;
import static ru.qatools.gridrouter.JsonWireUtils.*;
import static ru.qatools.gridrouter.RequestUtils.getRemoteHost;
/**
* @author Alexander Andyashin aandryashin@yandex-team.ru
* @author Innokenty Shuvalov innokenty@yandex-team.ru
* @author Dmitry Baev charlie@yandex-team.ru
* @author Artem Eroshenko eroshenkoam@yandex-team.ru
*/
@WebServlet(
urlPatterns = {WD_HUB_SESSION + "*"},
asyncSupported = true,
initParams = {
@WebInitParam(name = "timeout", value = "300000"),
@WebInitParam(name = "idleTimeout", value = "300000")
}
)
public class ProxyServlet extends org.eclipse.jetty.proxy.ProxyServlet {
private static final Logger LOGGER = LoggerFactory.getLogger(ProxyServlet.class);
@Autowired
private transient ConfigRepository config;
@Autowired
private transient StatsCounter statsCounter;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
processInjectionBasedOnServletContext(this, config.getServletContext());
}
@Override
protected void sendProxyRequest(
HttpServletRequest clientRequest, HttpServletResponse proxyResponse, Request proxyRequest) {
try {
Request request = getRequestWithoutSessionId(clientRequest, proxyRequest);
super.sendProxyRequest(clientRequest, proxyResponse, request);
} catch (Exception exception) {
LOGGER.error("[REQUEST_READ_FAILURE] [{}] - could not read client request, proxying request as is",
clientRequest.getRemoteHost(), exception);
super.sendProxyRequest(clientRequest, proxyResponse, proxyRequest);
}
}
@Override
protected String rewriteTarget(HttpServletRequest request) {
String uri = request.getRequestURI();
String remoteHost = getRemoteHost(request);
if (!isUriValid(uri)) {
LOGGER.warn("[INVALID_SESSION_HASH] [{}] - request uri is {}", remoteHost, uri);
return null;
}
String route = config.getRoute(getSessionHash(uri));
String command = getCommand(uri);
if (route == null) {
LOGGER.error("[ROUTE_NOT_FOUND] [{}] - request uri is {}", remoteHost, uri);
return null;
}
if (isSessionDeleteRequest(request, command)) {
LOGGER.info("[SESSION_DELETED] [{}] [{}] [{}]", remoteHost, route, command);
statsCounter.deleteSession(getFullSessionId(uri), route);
} else {
statsCounter.updateSession(getFullSessionId(uri), route);
}
try {
return redirectionUrl(route, command);
} catch (Exception exception) {
LOGGER.error("[REDIRECTION_URL_ERROR] [{}] - error building redirection uri because of {}\n"
+ " request uri: {}\n"
+ " parsed route: {}\n"
+ " parsed command: {}",
remoteHost, exception.toString(), uri, route, command);
}
return null;
}
protected Request getRequestWithoutSessionId(HttpServletRequest clientRequest, Request proxyRequest) throws IOException {
String content = IOUtils.toString(clientRequest.getInputStream(), UTF_8);
if (!content.isEmpty()) {
String remoteHost = getRemoteHost(clientRequest);
content = removeSessionIdSafe(content, remoteHost);
}
return proxyRequest.content(
new StringContentProvider(clientRequest.getContentType(), content, UTF_8));
}
private String removeSessionIdSafe(String content, String remoteHost) {
try {
JsonMessage message = JsonMessageFactory.from(content);
message.setSessionId(null);
return message.toJson();
} catch (IOException exception) {
LOGGER.error("[UNABLE_TO_REMOVE_SESSION_ID] [{}] - could not create proxy request without session id, "
+ "proxying request as is. Request content is: {}",
remoteHost, content, exception);
}
return content;
}
}