package com.intrbiz.bergamot.check.http; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.DefaultHttpHeaders; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpVersion; import java.net.URL; import java.util.Base64; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.Map.Entry; import java.util.function.Consumer; import com.intrbiz.Util; import com.intrbiz.bergamot.crypto.util.TLSConstants; import com.intrbiz.bergamot.crypto.util.TLSConstants.CipherInfo; /** * Fluent interface to construct a HTTP check */ public abstract class HTTPCheckBuilder { private String address; private int port = -1; private int connectTimeout = -1; private int requestTimeout = -1; private boolean ssl = false; private boolean permitInvalidCerts = false; private HttpVersion version = HttpVersion.HTTP_1_1; private HttpMethod method = HttpMethod.GET; private String virtualHost; private String path = "/"; private HttpHeaders headers = new DefaultHttpHeaders(); private Consumer<HTTPCheckResponse> responseHandler; private Consumer<Throwable> errorHandler; private List<String> ciphers = new LinkedList<String>(); private List<String> protocols = new LinkedList<String>(); private String username; private String password; public HTTPCheckBuilder() { super(); } public HTTPCheckBuilder connect(String address) { this.address = address; return this; } public HTTPCheckBuilder port(int port) { this.port = port; return this; } public HTTPCheckBuilder connect(String address, int port) { this.address = address; this.port = port; return this; } public HTTPCheckBuilder connectTimeout(int connectTimeout) { this.connectTimeout = connectTimeout; return this; } public HTTPCheckBuilder requestTimeout(int requestTimeout) { this.requestTimeout = requestTimeout; return this; } public HTTPCheckBuilder timeout(int connectTimeout, int requestTimeout) { this.connectTimeout = connectTimeout; this.requestTimeout = requestTimeout; return this; } public HTTPCheckBuilder http() { this.ssl = false; return this; } public HTTPCheckBuilder https() { this.ssl = true; return this; } public HTTPCheckBuilder ssl() { this.ssl = true; return this; } public HTTPCheckBuilder ssl(boolean ssl) { this.ssl = ssl; return this; } public HTTPCheckBuilder permitInvalidCerts() { this.permitInvalidCerts = true; return this; } public HTTPCheckBuilder permitInvalidCerts(boolean permitInvalidCerts) { this.permitInvalidCerts = permitInvalidCerts; return this; } public HTTPCheckBuilder enabledSSLCiphers(Collection<String> ciphers) { this.ciphers.addAll(ciphers); return this; } public HTTPCheckBuilder enabledSSLCiphers(String... ciphers) { for (String cipher : ciphers) { this.ciphers.add(cipher); } return this; } public HTTPCheckBuilder enableSSLCipher(String cipher) { this.ciphers.add(cipher); return this; } public HTTPCheckBuilder enabledSSLCiphers(CipherInfo... ciphers) { for (CipherInfo cipher : ciphers) { this.ciphers.add(cipher.getName()); } return this; } public HTTPCheckBuilder enabledSSLProtocols(Collection<String> protocols) { this.protocols.addAll(protocols); return this; } public HTTPCheckBuilder enabledSSLProtocols(String... protocols) { for (String protocol : protocols) { this.protocols.add(protocol); } return this; } public HTTPCheckBuilder enableSSLProtocol(String protocol) { this.protocols.add(protocol); return this; } public HTTPCheckBuilder enableSSLv3() { this.protocols.add(TLSConstants.PROTOCOLS.SSLv3); return this; } public HTTPCheckBuilder enableTLSv1() { this.protocols.add(TLSConstants.PROTOCOLS.TLSv1); return this; } public HTTPCheckBuilder enableTLSv1_1() { this.protocols.add(TLSConstants.PROTOCOLS.TLSv1_1); return this; } public HTTPCheckBuilder enableTLSv1_2() { this.protocols.add(TLSConstants.PROTOCOLS.TLSv1_2); return this; } public HTTPCheckBuilder version(HttpVersion version) { this.version = version; return this; } public HTTPCheckBuilder http1_0() { this.version = HttpVersion.HTTP_1_0; return this; } public HTTPCheckBuilder http1_1() { this.version = HttpVersion.HTTP_1_1; return this; } public HTTPCheckBuilder method(HttpMethod method) { this.method = method; return this; } public HTTPCheckBuilder path(String path) { this.path = path; return this; } public HTTPCheckBuilder get(String path) { this.method = HttpMethod.GET; this.path = path; return this; } public HTTPCheckBuilder get(URL url) { this.method = HttpMethod.GET; this.ssl = "https".equalsIgnoreCase(url.getProtocol()); this.address = url.getHost(); this.port = url.getPort(); this.path = url.getPath(); return this; } public HTTPCheckBuilder post(String path) { this.method = HttpMethod.POST; this.path = path; return this; } public HTTPCheckBuilder post(URL url) { this.method = HttpMethod.POST; this.ssl = "https".equalsIgnoreCase(url.getProtocol()); this.address = url.getHost(); this.port = url.getPort(); this.path = url.getPath(); return this; } public HTTPCheckBuilder post() { this.method = HttpMethod.POST; this.path = "/"; return this; } public HTTPCheckBuilder head(String path) { this.method = HttpMethod.HEAD; this.path = path; return this; } public HTTPCheckBuilder head(URL url) { this.method = HttpMethod.GET; this.ssl = "https".equalsIgnoreCase(url.getProtocol()); this.address = url.getHost(); this.port = url.getPort(); this.path = url.getPath(); return this; } public HTTPCheckBuilder head() { this.method = HttpMethod.HEAD; this.path = "/"; return this; } public HTTPCheckBuilder host(String virtualHost) { this.virtualHost = virtualHost; return this; } public HTTPCheckBuilder header(String name, Object value) { this.headers.add(name, value); return this; } public HTTPCheckBuilder basicAuth(String username, String password) { this.username = username; this.password = password; return this; } public HTTPCheckBuilder onResponse(Consumer<HTTPCheckResponse> responseHandler) { this.responseHandler = responseHandler; return this; } public HTTPCheckBuilder onError(Consumer<Throwable> errorHandler) { this.errorHandler = errorHandler; return this; } /* Executors */ public void execute(Consumer<HTTPCheckResponse> responseHandler, Consumer<Throwable> errorHandler) { this.responseHandler = responseHandler; this.errorHandler = errorHandler; this.execute(); } public void execute() { // default port if (this.port == -1) this.port = this.ssl ? 443 : 80; // default virtual host if (this.virtualHost == null) this.virtualHost = this.address; // build the request FullHttpRequest request = new DefaultFullHttpRequest(this.version, this.method, this.path); // default to connection close request.headers().add(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE); // virtual host if (this.port == 80 || this.port == 443) request.headers().add(HttpHeaders.Names.HOST, this.virtualHost); else request.headers().add(HttpHeaders.Names.HOST, this.virtualHost + ":" + this.port); // user agent request.headers().add(HttpHeaders.Names.USER_AGENT, "Bergamot Monitoring Check HTTP 1.0.0"); // HTTP auth if (! Util.isEmpty(this.username)) { String encodedCredentials = new String(Base64.getEncoder().encode((this.username + ":" + Util.coalesce(this.password, "")).getBytes(Util.UTF8)), Util.UTF8); request.headers().add(HttpHeaders.Names.AUTHORIZATION, "Basic " + encodedCredentials); } // add headers for (Entry<String, String> e : this.headers) { request.headers().add(e.getKey(), e.getValue()); } // submit the check this.submit( this.address, this.port, this.connectTimeout, this.requestTimeout, this.ssl, this.permitInvalidCerts, this.virtualHost, this.protocols, this.ciphers, request, this.responseHandler, this.errorHandler ); } protected abstract void submit( final String address, final int port, final int connectTimeout, final int requestTimeout, final boolean ssl, final boolean permitInvalidCerts, final String SNIHost, final List<String> protocols, final List<String> ciphers, final FullHttpRequest request, final Consumer<HTTPCheckResponse> responseHandler, final Consumer<Throwable> errorHandler ); }