use of org.carapaceproxy.server.config.BackendConfiguration in project carapaceproxy by diennea.
the class BasicStandardEndpointMapperTest method test.
@Test
public void test() throws Exception {
stubFor(get(urlEqualTo("/index.html")).willReturn(aResponse().withStatus(200).withHeader("Content-Type", "text/html").withBody("it <b>works</b> !!")));
stubFor(get(urlEqualTo("/index2.html")).willReturn(aResponse().withStatus(200).withHeader("Content-Type", "text/html").withBody("it <b>works</b> !!")));
stubFor(get(urlEqualTo("/index3.html")).willReturn(aResponse().withStatus(200).withHeader("Content-Type", "text/html").withBody("it <b>works</b> !!")));
int backendPort = backend1.port();
StandardEndpointMapper mapper = new StandardEndpointMapper();
mapper.addBackend(new BackendConfiguration("backend-a", "localhost", backendPort, "/"));
mapper.addBackend(new BackendConfiguration("backend-b", "localhost", backendPort, "/"));
mapper.addDirector(new DirectorConfiguration("director-1").addBackend("backend-a"));
mapper.addDirector(new DirectorConfiguration("director-2").addBackend("backend-b"));
// all of the known backends
mapper.addDirector(new DirectorConfiguration("director-all").addBackend("*"));
mapper.addAction(new ActionConfiguration("proxy-1", ActionConfiguration.TYPE_PROXY, "director-1", null, -1));
mapper.addAction(new ActionConfiguration("cache-1", ActionConfiguration.TYPE_CACHE, "director-2", null, -1));
mapper.addAction(new ActionConfiguration("all-1", ActionConfiguration.TYPE_CACHE, "director-all", null, -1));
mapper.addAction(new ActionConfiguration("not-found-custom", ActionConfiguration.TYPE_STATIC, null, StaticContentsManager.DEFAULT_NOT_FOUND, 404));
mapper.addAction(new ActionConfiguration("error-custom", ActionConfiguration.TYPE_STATIC, null, StaticContentsManager.DEFAULT_INTERNAL_SERVER_ERROR, 500));
mapper.addAction(new ActionConfiguration("static-custom", ActionConfiguration.TYPE_STATIC, null, CLASSPATH_RESOURCE + "/test-static-page.html", 200));
mapper.addRoute(new RouteConfiguration("route-1", "proxy-1", true, new RegexpRequestMatcher(PROPERTY_URI, ".*index.html.*")));
mapper.addRoute(new RouteConfiguration("route-1b", "cache-1", true, new RegexpRequestMatcher(PROPERTY_URI, ".*index2.html.*")));
mapper.addRoute(new RouteConfiguration("route-1c", "all-1", true, new RegexpRequestMatcher(PROPERTY_URI, ".*index3.html.*")));
mapper.addRoute(new RouteConfiguration("route-2-not-found", "not-found-custom", true, new RegexpRequestMatcher(PROPERTY_URI, ".*notfound.html.*")));
mapper.addRoute(new RouteConfiguration("route-3-error", "error-custom", true, new RegexpRequestMatcher(PROPERTY_URI, ".*error.html.*")));
mapper.addRoute(new RouteConfiguration("route-4-static", "static-custom", true, new RegexpRequestMatcher(PROPERTY_URI, ".*static.html.*")));
try (HttpProxyServer server = HttpProxyServer.buildForTests("localhost", 0, mapper, tmpDir.newFolder())) {
server.start();
int port = server.getLocalPort();
{
// proxy on director 1
String s = IOUtils.toString(new URL("http://localhost:" + port + "/index.html").toURI(), "utf-8");
assertEquals("it <b>works</b> !!", s);
}
{
// cache on director 2
String s = IOUtils.toString(new URL("http://localhost:" + port + "/index2.html").toURI(), "utf-8");
assertEquals("it <b>works</b> !!", s);
}
{
// director "all"
String s = IOUtils.toString(new URL("http://localhost:" + port + "/index3.html").toURI(), "utf-8");
assertEquals("it <b>works</b> !!", s);
}
try {
IOUtils.toString(new URL("http://localhost:" + port + "/notfound.html").toURI(), "utf-8");
fail("expected 404");
} catch (FileNotFoundException ok) {
}
{
String staticContent = IOUtils.toString(new URL("http://localhost:" + port + "/static.html").toURI(), "utf-8");
assertEquals("Test static page", staticContent);
}
{
String staticContent = IOUtils.toString(new URL("http://localhost:" + port + "/static.html").toURI(), "utf-8");
assertEquals("Test static page", staticContent);
}
try {
IOUtils.toString(new URL("http://localhost:" + port + "/error.html").toURI(), "utf-8");
fail("expected 500");
} catch (IOException ok) {
}
try {
IOUtils.toString(new URL("http://localhost:" + port + "/notmapped.html").toURI(), "utf-8");
fail("expected 404");
} catch (FileNotFoundException ok) {
}
}
}
use of org.carapaceproxy.server.config.BackendConfiguration in project carapaceproxy by diennea.
the class BasicStandardEndpointMapperTest method testDefaultRoute.
@Test
public void testDefaultRoute() throws Exception {
stubFor(get(urlEqualTo("/index.html")).willReturn(aResponse().withStatus(200).withHeader("Content-Type", "text/html").withBody("it <b>works</b> !!")));
stubFor(get(urlEqualTo("/notmapped.html")).willReturn(aResponse().withStatus(200).withHeader("Content-Type", "text/html").withBody("it <b>works</b> !!")));
stubFor(get(urlEqualTo("/down.html")).willReturn(aResponse().withStatus(200).withHeader("Content-Type", "text/html").withBody("it <b>works</b> !!")));
int backendPort = backend1.port();
StandardEndpointMapper mapper = new StandardEndpointMapper();
mapper.addBackend(new BackendConfiguration("backend", "localhost", backendPort, "/"));
mapper.addBackend(new BackendConfiguration("backend-down", "localhost-down", backendPort, "/"));
mapper.addDirector(new DirectorConfiguration("director").addBackend("backend"));
mapper.addDirector(new DirectorConfiguration("director-down").addBackend("backend-down"));
mapper.addAction(new ActionConfiguration("cache", ActionConfiguration.TYPE_CACHE, "director", null, -1));
mapper.addAction(new ActionConfiguration("cache-down", ActionConfiguration.TYPE_CACHE, "director-down", null, -1));
mapper.addRoute(new RouteConfiguration("route", "cache", true, new RegexpRequestMatcher(PROPERTY_URI, ".*index.html.*")));
mapper.addRoute(new RouteConfiguration("route-down", "cache-down", true, new RegexpRequestMatcher(PROPERTY_URI, ".*down.html.*")));
mapper.addRoute(new RouteConfiguration("route-default", "cache", true, new RegexpRequestMatcher(PROPERTY_URI, ".*html")));
BackendHealthManager bhMan = mock(BackendHealthManager.class);
when(bhMan.isAvailable(eq("localhost:" + backendPort))).thenReturn(true);
// simulate unreachable backend -> expected 500 error
when(bhMan.isAvailable(eq("localhost-down:" + backendPort))).thenReturn(false);
try (HttpProxyServer server = HttpProxyServer.buildForTests("localhost", 0, mapper, tmpDir.newFolder())) {
server.setBackendHealthManager(bhMan);
server.start();
int port = server.getLocalPort();
// index.html matches with route
{
String s = IOUtils.toString(new URL("http://localhost:" + port + "/index.html").toURI(), "utf-8");
assertEquals("it <b>works</b> !!", s);
}
// notmapped.html matches with route-default
{
String s = IOUtils.toString(new URL("http://localhost:" + port + "/notmapped.html").toURI(), "utf-8");
assertEquals("it <b>works</b> !!", s);
}
// down.html (request to unreachable backend) has NOT to match to route-deafult BUT get internal-error
try {
IOUtils.toString(new URL("http://localhost:" + port + "/down.html").toURI(), "utf-8");
fail("expected 500");
} catch (IOException ok) {
}
}
}
use of org.carapaceproxy.server.config.BackendConfiguration in project carapaceproxy by diennea.
the class ForceBackendTest method test.
@Test
public void test() throws Exception {
stubFor(get(urlEqualTo("/index.html?thedirector=director-2")).willReturn(aResponse().withStatus(200).withHeader("Content-Type", "text/html").withBody("it <b>works</b> !!")));
stubFor(get(urlEqualTo("/index.html?thebackend=backend-b")).willReturn(aResponse().withStatus(200).withHeader("Content-Type", "text/html").withBody("it <b>works</b> !!")));
int backendPort = backend1.port();
StandardEndpointMapper mapper = new StandardEndpointMapper();
Properties properties = new Properties();
properties.put("mapper.forcedirector.parameter", "thedirector");
properties.put("mapper.forcebackend.parameter", "thebackend");
mapper.configure(new PropertiesConfigurationStore(properties));
assertEquals("thedirector", mapper.getForceDirectorParameter());
assertEquals("thebackend", mapper.getForceBackendParameter());
mapper.addBackend(new BackendConfiguration("backend-a", "localhost", backendPort, "/"));
mapper.addBackend(new BackendConfiguration("backend-b", "localhost", backendPort, "/"));
mapper.addDirector(new DirectorConfiguration("director-1").addBackend("backend-a"));
mapper.addDirector(new DirectorConfiguration("director-2").addBackend("backend-b"));
mapper.addAction(new ActionConfiguration("proxy-1", ActionConfiguration.TYPE_PROXY, "director-1", null, -1));
mapper.addRoute(new RouteConfiguration("route-1", "proxy-1", true, new RegexpRequestMatcher(PROPERTY_URI, ".*index.html.*")));
try (HttpProxyServer server = HttpProxyServer.buildForTests("localhost", 0, mapper, tmpDir.newFolder())) {
server.start();
int port = server.getLocalPort();
{
// proxy on director 2
String s = IOUtils.toString(new URL("http://localhost:" + port + "/index.html?thedirector=director-2").toURI(), "utf-8");
assertEquals("it <b>works</b> !!", s);
}
{
// proxy on backend 2
String s = IOUtils.toString(new URL("http://localhost:" + port + "/index.html?thebackend=backend-b").toURI(), "utf-8");
assertEquals("it <b>works</b> !!", s);
}
}
}
use of org.carapaceproxy.server.config.BackendConfiguration in project carapaceproxy by diennea.
the class StandardEndpointMapper method map.
@Override
public MapResult map(ProxyRequest request) {
for (RouteConfiguration route : routes) {
if (!route.isEnabled()) {
continue;
}
boolean matchResult = route.matches(request);
if (LOG.isLoggable(Level.FINER)) {
LOG.log(Level.FINER, "route {0}, map {1} -> {2}", new Object[] { route.getId(), request.getUri(), matchResult });
}
if (matchResult) {
ActionConfiguration action = actions.get(route.getAction());
if (action == null) {
LOG.log(Level.INFO, "no action ''{0}'' -> not-found for {1}, valid {2}", new Object[] { route.getAction(), request.getUri(), actions.keySet() });
return MapResult.internalError(route.getId());
}
if (ActionConfiguration.TYPE_REDIRECT.equals(action.getType())) {
return MapResult.builder().host(action.getRedirectHost()).port(action.getRedirectPort()).action(MapResult.Action.REDIRECT).routeId(route.getId()).redirectLocation(action.getRedirectLocation()).redirectProto(action.getRedirectProto()).redirectPath(action.getRedirectPath()).errorCode(action.getErrorCode()).customHeaders(action.getCustomHeaders()).build();
}
if (ActionConfiguration.TYPE_STATIC.equals(action.getType())) {
return MapResult.builder().action(MapResult.Action.STATIC).routeId(route.getId()).resource(action.getFile()).errorCode(action.getErrorCode()).customHeaders(action.getCustomHeaders()).build();
}
if (ActionConfiguration.TYPE_ACME_CHALLENGE.equals(action.getType())) {
String tokenName = request.getUri().replaceFirst(".*" + ACME_CHALLENGE_URI_PATTERN, "");
String tokenData = parent.getDynamicCertificatesManager().getChallengeToken(tokenName);
if (tokenData == null) {
return MapResult.notFound(route.getId());
}
return MapResult.builder().action(MapResult.Action.ACME_CHALLENGE).routeId(route.getId()).resource(IN_MEMORY_RESOURCE + tokenData).errorCode(action.getErrorCode()).build();
}
UrlEncodedQueryString queryString = request.getQueryString();
String director = action.getDirector();
String forceBackendParameterValue = queryString.get(forceBackendParameter);
final List<String> selectedBackends;
if (forceBackendParameterValue != null) {
LOG.log(Level.INFO, "forcing backend = {0} for {1}", new Object[] { forceBackendParameterValue, request.getUri() });
selectedBackends = Collections.singletonList(forceBackendParameterValue);
} else {
String forceDirectorParameterValue = queryString.get(forceDirectorParameter);
if (forceDirectorParameterValue != null) {
director = forceDirectorParameterValue;
LOG.log(Level.INFO, "forcing director = {0} for {1}", new Object[] { director, request.getUri() });
}
selectedBackends = backendSelector.selectBackends(request.getUserId(), request.getSessionId(), director);
}
LOG.log(Level.FINEST, "selected {0} backends for {1}, director is {2}", new Object[] { selectedBackends, request.getUri(), director });
for (String backendId : selectedBackends) {
Action selectedAction;
switch(action.getType()) {
case ActionConfiguration.TYPE_PROXY:
selectedAction = MapResult.Action.PROXY;
break;
case ActionConfiguration.TYPE_CACHE:
selectedAction = MapResult.Action.CACHE;
break;
default:
return MapResult.internalError(route.getId());
}
BackendConfiguration backend = this.backends.get(backendId);
if (backend != null && parent.getBackendHealthManager().isAvailable(backend.getHostPort())) {
List<CustomHeader> customHeaders = action.getCustomHeaders();
if (this.debuggingHeaderEnabled) {
customHeaders = new ArrayList(customHeaders);
String routingPath = route.getId() + ";" + action.getId() + ";" + action.getDirector() + ";" + backendId;
customHeaders.add(new CustomHeader(DEBUGGING_HEADER_ID, debuggingHeaderName, routingPath, HeaderMode.ADD));
}
return MapResult.builder().host(backend.getHost()).port(backend.getPort()).action(selectedAction).routeId(route.getId()).customHeaders(customHeaders).build();
}
}
// none of selected backends available
if (!selectedBackends.isEmpty()) {
return MapResult.internalError(route.getId());
}
}
}
// no one route matched
return MapResult.notFound(MapResult.NO_ROUTE);
}
use of org.carapaceproxy.server.config.BackendConfiguration in project carapaceproxy by diennea.
the class HttpProxyServer method applyDynamicConfiguration.
private void applyDynamicConfiguration(ConfigurationStore newConfigurationStore, boolean atBoot) throws InterruptedException, ConfigurationChangeInProgressException {
if (atBoot && newConfigurationStore != null) {
throw new IllegalStateException();
}
if (!atBoot && newConfigurationStore == null) {
throw new IllegalStateException();
}
// at boot we are constructing a configuration from the database
// if the system is already "up" we have to only apply the new config
ConfigurationStore storeWithConfig = atBoot ? dynamicConfigurationStore : newConfigurationStore;
if (!configurationLock.tryLock()) {
throw new ConfigurationChangeInProgressException();
}
try {
RuntimeServerConfiguration newConfiguration = buildValidConfiguration(storeWithConfig);
EndpointMapper newMapper = buildMapper(newConfiguration.getMapperClassname(), storeWithConfig);
newMapper.setParent(this);
UserRealm newRealm = buildRealm(userRealmClassname, storeWithConfig);
this.filters = buildFilters(newConfiguration);
this.backendHealthManager.reloadConfiguration(newConfiguration, newMapper);
this.dynamicCertificatesManager.reloadConfiguration(newConfiguration);
this.ocspStaplingManager.reloadConfiguration(newConfiguration);
this.listeners.reloadConfiguration(newConfiguration);
this.cache.reloadConfiguration(newConfiguration);
this.requestsLogger.reloadConfiguration(newConfiguration);
this.realm = newRealm;
Map<String, BackendConfiguration> currentBackends = mapper != null ? mapper.getBackends() : Collections.emptyMap();
Map<String, BackendConfiguration> newBackends = newMapper.getBackends();
this.mapper = newMapper;
if (atBoot || !newBackends.equals(currentBackends) || isConnectionsConfigurationChanged(newConfiguration)) {
prometheusRegistry.clear();
Metrics.globalRegistry.clear();
proxyRequestsManager.reloadConfiguration(newConfiguration, newBackends.values());
}
if (!atBoot) {
dynamicConfigurationStore.commitConfiguration(newConfigurationStore);
}
this.currentConfiguration = newConfiguration;
} catch (ConfigurationNotValidException err) {
// impossible to have a non valid configuration here
throw new IllegalStateException(err);
} finally {
configurationLock.unlock();
}
}
Aggregations