Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: rework classes around backend health tracking and mapping #516

Merged
merged 8 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
*/
package org.carapaceproxy;

import java.util.Collections;
import io.netty.handler.codec.http.HttpResponseStatus;
import java.util.List;
import org.carapaceproxy.server.mapper.CustomHeader;

Expand All @@ -28,53 +28,29 @@
*
* @author paolo.venturi
*/
public class SimpleHTTPResponse {
public record SimpleHTTPResponse(int errorCode, String resource, List<CustomHeader> customHeaders) {

private final int errorcode;
private final String resource;
private final List<CustomHeader> customHeaders;

public SimpleHTTPResponse(int errorcode, String resource, List<CustomHeader> customHeaders) {
this.errorcode = errorcode;
this.resource = resource;
this.customHeaders = customHeaders == null ? Collections.emptyList() : Collections.unmodifiableList(customHeaders);
}

public int getErrorcode() {
return errorcode;
}

public String getResource() {
return resource;
public SimpleHTTPResponse {
customHeaders = List.copyOf(customHeaders);
}

public List<CustomHeader> getCustomHeaders() {
return customHeaders;
public SimpleHTTPResponse(final int errorCode, final String resource) {
this(errorCode, resource, List.of());
}

public static final SimpleHTTPResponse NOT_FOUND(String res) {
return new SimpleHTTPResponse(404, res, null);
public static SimpleHTTPResponse notFound(final String resource) {
return new SimpleHTTPResponse(HttpResponseStatus.NOT_FOUND.code(), resource);
}

public static final SimpleHTTPResponse INTERNAL_ERROR(String res) {
return new SimpleHTTPResponse(500, res, null);
public static SimpleHTTPResponse internalError(final String resource) {
return new SimpleHTTPResponse(HttpResponseStatus.INTERNAL_SERVER_ERROR.code(), resource);
}

public static final SimpleHTTPResponse MAINTENANCE_MODE(String res) {
return new SimpleHTTPResponse(500, res, null);
public static SimpleHTTPResponse badRequest(final String resource) {
return new SimpleHTTPResponse(HttpResponseStatus.BAD_REQUEST.code(), resource);
}

public static final SimpleHTTPResponse BAD_REQUEST(String res) {
return new SimpleHTTPResponse(400, res, null);
public static SimpleHTTPResponse serviceUnavailable(final String resource) {
return new SimpleHTTPResponse(HttpResponseStatus.SERVICE_UNAVAILABLE.code(), resource);
}

public static final SimpleHTTPResponse SERVICE_UNAVAILABLE(String res) {
return new SimpleHTTPResponse(503, res, null);
}

@Override
public String toString() {
return "SimpleHTTPResponse{" + "errorcode=" + errorcode + ", resource=" + resource + ", customHeaders=" + customHeaders + '}';
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,10 @@ public Map<String, BackendBean> getAll() {
bean.reportedAsUnreachableTs = bhs.getReportedAsUnreachableTs();
BackendHealthCheck lastProbe = bhs.getLastProbe();
if (lastProbe != null) {
bean.lastProbeTs = lastProbe.getEndTs();
bean.lastProbeTs = lastProbe.endTs();
bean.lastProbeSuccess = lastProbe.isOk();
bean.httpResponse = lastProbe.getHttpResponse();
bean.httpBody = lastProbe.getHttpBody();
bean.httpResponse = lastProbe.httpResponse();
bean.httpBody = lastProbe.httpBody();
}
}
res.put(id, bean);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
*/
package org.carapaceproxy.api;

import static org.carapaceproxy.server.mapper.StandardEndpointMapper.ACME_CHALLENGE_ROUTE_ACTION_ID;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.carapaceproxy.core.HttpProxyServer;
import static org.carapaceproxy.server.mapper.StandardEndpointMapper.ACME_CHALLENGE_ROUTE_ACTION_ID;

/**
* Access to configured routes
Expand Down Expand Up @@ -77,24 +77,25 @@ public String getMatcher() {
return matcher;
}

public String getMaintenanceAction() { return maintenanceAction; }
public String getMaintenanceAction() {
return maintenanceAction;
}
}

@GET
public List<RouteBean> getAll() {
final List<RouteBean> routes = new ArrayList();
final List<RouteBean> routes = new ArrayList<>();
HttpProxyServer server = (HttpProxyServer) context.getAttribute("server");
server.getMapper().getRoutes().stream()
.filter(r -> !r.getId().equals(ACME_CHALLENGE_ROUTE_ACTION_ID))
.forEach(route -> {
routes.add(new RouteBean(
route.getId(),
route.getAction(),
route.getErrorAction(),
route.isEnabled(),
route.getMatcher().getDescription(),
route.getMaintenanceModeAction()));
});
.forEach(route -> routes.add(new RouteBean(
route.getId(),
route.getAction(),
route.getErrorAction(),
route.isEnabled(),
route.getMatcher().getDescription(),
route.getMaintenanceModeAction()
)));

return routes;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,13 +369,13 @@ public Future<SslContext> map(String sniHostname, Promise<SslContext> promise) {

sslContext = sslContexts.computeIfAbsent(key, (k) -> {
try {
SSLCertificateConfiguration choosen = chooseCertificate(sniHostname, config.getDefaultCertificate());
if (choosen == null) {
SSLCertificateConfiguration chosen = chooseCertificate(sniHostname, config.getDefaultCertificate());
if (chosen == null) {
throw new ConfigurationNotValidException("cannot find a certificate for snihostname " + sniHostname
+ ", with default cert for listener as '" + config.getDefaultCertificate()
+ "', available " + currentConfiguration.getCertificates().keySet());
}
return bootSslContext(config, choosen);
return bootSslContext(config, chosen);
} catch (ConfigurationNotValidException ex) {
throw new RuntimeException(ex);
}
Expand Down Expand Up @@ -464,16 +464,16 @@ public SSLCertificateConfiguration chooseCertificate(String sniHostname, String
}
}
}
SSLCertificateConfiguration choosen = null;
SSLCertificateConfiguration chosen = null;
if (certificateMatchExact != null) {
choosen = certificateMatchExact;
chosen = certificateMatchExact;
} else if (certificateMatchNoExact != null) {
choosen = certificateMatchNoExact;
chosen = certificateMatchNoExact;
}
if (choosen == null) {
choosen = certificates.get(defaultCertificate);
if (chosen == null) {
chosen = certificates.get(defaultCertificate);
}
return choosen;
return chosen;
}

private static boolean certificateMatches(String hostname, SSLCertificateConfiguration c, boolean exact) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@
import io.netty.handler.codec.http2.Http2Headers;
import io.netty.handler.ssl.SslHandler;
import java.net.InetSocketAddress;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;
import lombok.Data;
import org.carapaceproxy.server.filters.UrlEncodedQueryString;
import org.carapaceproxy.server.mapper.MapResult;
import org.carapaceproxy.server.mapper.requestmatcher.MatchingContext;
import org.carapaceproxy.utils.StringUtils;
import org.reactivestreams.Publisher;
import reactor.netty.ByteBufFlux;
import reactor.netty.http.server.HttpServerRequest;
Expand All @@ -51,24 +54,24 @@
@Data
public class ProxyRequest implements MatchingContext {

private static final Pattern NETTY_HTTP_1_VERSION_PATTERN =
Pattern.compile("(\\S+)/(\\d+)\\.(\\d+)");

// All properties name have been converted to lowercase during parsing
public static final String PROPERTY_URI = "request.uri";
public static final String PROPERTY_METHOD = "request.method";
public static final String PROPERTY_CONTENT_TYPE = "request.content-type";
public static final String PROPERTY_HEADERS = "request.headers.";
public static final String PROPERTY_LISTENER_HOST_PORT = "listener.hostport";
public static final String PROPERTY_LISTENER_IPADDRESS = "listener.ipaddress";

private static final Pattern NETTY_HTTP_1_VERSION_PATTERN = Pattern.compile("(\\S+)/(\\d+)\\.(\\d+)");
private static final int HEADERS_SUBSTRING_INDEX = PROPERTY_HEADERS.length();
private static final AtomicLong REQUESTS_ID_GENERATOR = new AtomicLong();

private final long id = REQUESTS_ID_GENERATOR.incrementAndGet();
private final HttpServerRequest request;
private final HttpServerResponse response;
private final EndpointKey listener;
private final HttpVersion httpProtocol;
private final String sslProtocol;
private final String cipherSuite;
private MapResult action;
private String userId;
private String sessionId;
Expand All @@ -77,12 +80,11 @@ public class ProxyRequest implements MatchingContext {
private volatile long lastActivity;
private String uri;
private UrlEncodedQueryString queryString;
private String sslProtocol;
private String cipherSuite;
private boolean servedFromCache;
private HttpVersion httpProtocol;

public ProxyRequest(HttpServerRequest request, HttpServerResponse response, EndpointKey listener) {
public ProxyRequest(
final HttpServerRequest request, final HttpServerResponse response, final EndpointKey listener
) {
this.request = request;
this.response = response;
this.listener = listener;
Expand All @@ -94,13 +96,27 @@ public ProxyRequest(HttpServerRequest request, HttpServerResponse response, Endp
} else {
throw new IllegalArgumentException("Unsupported request protocol: " + protocol);
}
request.withConnection(conn -> {
SslHandler handler = conn.channel().pipeline().get(SslHandler.class);
if (handler != null) {
sslProtocol = handler.engine().getSession().getProtocol();
cipherSuite = handler.engine().getSession().getCipherSuite();
}
});
final SslHandler handler = getSslHandler();
if (handler != null) {
this.sslProtocol = handler.engine().getSession().getProtocol();
this.cipherSuite = handler.engine().getSession().getCipherSuite();
} else {
this.sslProtocol = null;
this.cipherSuite = null;
}
}

public static UrlEncodedQueryString parseQueryString(final String uri) {
int pos = uri.indexOf('?');
return pos < 0 || pos == uri.length() - 1
? UrlEncodedQueryString.create()
: UrlEncodedQueryString.parse(uri.substring(pos + 1));
}

private SslHandler getSslHandler() {
final AtomicReference<SslHandler> sslHandlerRef = new AtomicReference<>();
request.withConnection(conn -> sslHandlerRef.set(conn.channel().pipeline().get(SslHandler.class)));
return sslHandlerRef.get();
}

@Override
Expand All @@ -121,15 +137,15 @@ public String getProperty(String name) {

@Override
public boolean isSecure() {
return request.scheme().equalsIgnoreCase(HttpScheme.HTTPS + "");
return HttpScheme.HTTPS.name().contentEqualsIgnoreCase(request.scheme());
}

public InetSocketAddress getLocalAddress() {
return request.hostAddress();
return Objects.requireNonNull(request.hostAddress());
}

public InetSocketAddress getRemoteAddress() {
return request.remoteAddress();
return Objects.requireNonNull(request.remoteAddress());
}

/**
Expand All @@ -149,18 +165,18 @@ public String getUri() {
uri = uri.substring(schemePrefix.length());
}
String fullPath = request.fullPath();
if (fullPath != null && !fullPath.isBlank()) {
int pos = uri.indexOf(request.fullPath());
if (pos > 0) {
uri = uri.substring(pos);
}
} else {
if (StringUtils.isBlank(fullPath)) {
int queryStringPos = uri.indexOf("?");
if (queryStringPos >= 0) {
uri = "/" + uri.substring(queryStringPos);
} else {
uri = "/";
}
} else {
int pos = uri.indexOf(request.fullPath());
if (pos > 0) {
uri = uri.substring(pos);
}
}

return uri;
Expand Down Expand Up @@ -192,7 +208,7 @@ public String getRequestHostname() {
return request.requestHeaders().get(HttpHeaderNames.HOST);
}

public boolean isValidHostAndPort(String hostAndPort) {
public boolean isValidHostAndPort(final String hostAndPort) {
try {
if (hostAndPort == null) {
return false;
Expand Down Expand Up @@ -221,13 +237,6 @@ public UrlEncodedQueryString getQueryString() {
return queryString;
}

public static UrlEncodedQueryString parseQueryString(String uri) {
int pos = uri.indexOf('?');
return pos < 0 || pos == uri.length() - 1
? UrlEncodedQueryString.create()
: UrlEncodedQueryString.parse(uri.substring(pos + 1));
}

public HttpHeaders getRequestHeaders() {
return request.requestHeaders();
}
Expand Down
Loading
Loading