@Override public void customize(Connector connector, HttpConfiguration channelConfig, Request request) { EndPoint endp = request.getHttpChannel().getEndPoint(); if (endp instanceof DecryptedEndPoint) { SslConnection.DecryptedEndPoint ssl_endp = (DecryptedEndPoint) endp; SslConnection sslConnection = ssl_endp.getSslConnection(); SSLEngine sslEngine = sslConnection.getSSLEngine(); customize(sslEngine, request); if (request.getHttpURI().getScheme() == null) request.setScheme(HttpScheme.HTTPS.asString()); } else if (endp instanceof ProxyConnectionFactory.ProxyEndPoint) { ProxyConnectionFactory.ProxyEndPoint proxy = (ProxyConnectionFactory.ProxyEndPoint) endp; if (request.getHttpURI().getScheme() == null && proxy.getAttribute(ProxyConnectionFactory.TLS_VERSION) != null) request.setScheme(HttpScheme.HTTPS.asString()); } if (HttpScheme.HTTPS.is(request.getScheme())) customizeSecure(request); }
@Override public void succeeded(Connection connection) { HttpDestination destination = (HttpDestination) context.get(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY); if (HttpScheme.HTTPS.is(destination.getScheme())) { SslContextFactory sslContextFactory = destination.getHttpClient().getSslContextFactory(); if (sslContextFactory != null) { tunnel(destination, connection); } else { String message = String.format( "Cannot perform requests over SSL, no %s in %s", SslContextFactory.class.getSimpleName(), HttpClient.class.getSimpleName()); promise.failed(new IllegalStateException(message)); } } else { promise.succeeded(connection); } }
public HttpDestination(HttpClient client, Origin origin) { this.client = client; this.origin = origin; this.exchanges = newExchangeQueue(client); this.requestNotifier = new RequestNotifier(client); this.responseNotifier = new ResponseNotifier(); ProxyConfiguration proxyConfig = client.getProxyConfiguration(); proxy = proxyConfig.match(origin); ClientConnectionFactory connectionFactory = client.getTransport(); if (proxy != null) { connectionFactory = proxy.newClientConnectionFactory(connectionFactory); } else { if (HttpScheme.HTTPS.is(getScheme())) connectionFactory = newSslClientConnectionFactory(connectionFactory); } this.connectionFactory = connectionFactory; String host = getHost(); if (!client.isDefaultPort(getScheme(), getPort())) host += ":" + getPort(); hostField = new HttpField(HttpHeader.HOST, host); }
/** * HTTP Configuration. * * <p>This class is a holder of HTTP configuration for use by the {@link HttpChannel} class. * Typically a HTTPConfiguration instance is instantiated and passed to a {@link ConnectionFactory} * that can create HTTP channels (eg HTTP, AJP or SPDY). * * <p>The configuration held by this class is not for the wire protocol, but for the interpretation * and handling of HTTP requests that could be transported by a variety of protocols. */ @ManagedObject("HTTP Configuration") public class HttpConfiguration { private List<Customizer> _customizers = new CopyOnWriteArrayList<>(); private int _outputBufferSize = 32 * 1024; private int _requestHeaderSize = 8 * 1024; private int _responseHeaderSize = 8 * 1024; private int _headerCacheSize = 512; private int _securePort; private String _secureScheme = HttpScheme.HTTPS.asString(); private boolean _sendServerVersion = true; // send Server: header private boolean _sendXPoweredBy = false; // send X-Powered-By: header private boolean _sendDateHeader = false; // send Date: header public interface Customizer { public void customize(Connector connector, HttpConfiguration channelConfig, Request request); } public interface ConnectionFactory { HttpConfiguration getHttpConfiguration(); } public HttpConfiguration() {} /* ------------------------------------------------------------ */ /** * Create a configuration from another. * * @param config The configuration to copy. */ public HttpConfiguration(HttpConfiguration config) { _customizers.addAll(config._customizers); _outputBufferSize = config._outputBufferSize; _requestHeaderSize = config._requestHeaderSize; _responseHeaderSize = config._responseHeaderSize; _securePort = config._securePort; _secureScheme = config._secureScheme; _sendDateHeader = config._sendDateHeader; _sendServerVersion = config._sendServerVersion; _headerCacheSize = config._headerCacheSize; } /* ------------------------------------------------------------ */ /** * Add a {@link Customizer} that is invoked for every request received. * * <p>Customiser are often used to interpret optional headers (eg {@link * ForwardedRequestCustomizer}) or optional protocol semantics (eg {@link * SecureRequestCustomizer}). * * @param customizer A request customizer */ public void addCustomizer(Customizer customizer) { _customizers.add(customizer); } /* ------------------------------------------------------------ */ public List<Customizer> getCustomizers() { return _customizers; } public <T> T getCustomizer(Class<T> type) { for (Customizer c : _customizers) if (type.isAssignableFrom(c.getClass())) return (T) c; return null; } @ManagedAttribute("The size in bytes of the output buffer used to aggregate HTTP output") public int getOutputBufferSize() { return _outputBufferSize; } @ManagedAttribute("The maximum allowed size in bytes for a HTTP request header") public int getRequestHeaderSize() { return _requestHeaderSize; } @ManagedAttribute("The maximum allowed size in bytes for a HTTP response header") public int getResponseHeaderSize() { return _responseHeaderSize; } @ManagedAttribute("The maximum allowed size in bytes for a HTTP header field cache") public int getHeaderCacheSize() { return _headerCacheSize; } @ManagedAttribute( "The port to which Integral or Confidential security constraints are redirected") public int getSecurePort() { return _securePort; } @ManagedAttribute( "The scheme with which Integral or Confidential security constraints are redirected") public String getSecureScheme() { return _secureScheme; } public void setSendServerVersion(boolean sendServerVersion) { _sendServerVersion = sendServerVersion; } @ManagedAttribute("if true, send the Server header in responses") public boolean getSendServerVersion() { return _sendServerVersion; } public void setSendXPoweredBy(boolean sendXPoweredBy) { _sendXPoweredBy = sendXPoweredBy; } @ManagedAttribute("if true, send the X-Powered-By header in responses") public boolean getSendXPoweredBy() { return _sendXPoweredBy; } public void setSendDateHeader(boolean sendDateHeader) { _sendDateHeader = sendDateHeader; } @ManagedAttribute("if true, include the date in HTTP headers") public boolean getSendDateHeader() { return _sendDateHeader; } /* ------------------------------------------------------------ */ /** * Set the {@link Customizer}s that are invoked for every request received. * * <p>Customisers are often used to interpret optional headers (eg {@link * ForwardedRequestCustomizer}) or optional protocol semantics (eg {@link * SecureRequestCustomizer}). * * @param customizers */ public void setCustomizers(List<Customizer> customizers) { _customizers.clear(); _customizers.addAll(customizers); } /* ------------------------------------------------------------ */ /** * Set the size of the buffer into which response content is aggregated before being sent to the * client. A larger buffer can improve performance by allowing a content producer to run without * blocking, however larger buffers consume more memory and may induce some latency before a * client starts processing the content. * * @param responseBufferSize buffer size in bytes. */ public void setOutputBufferSize(int responseBufferSize) { _outputBufferSize = responseBufferSize; } /* ------------------------------------------------------------ */ /** * Set the maximum size of a request header. * * <p>Larger headers will allow for more and/or larger cookies plus larger form content encoded in * a URL. However, larger headers consume more memory and can make a server more vulnerable to * denial of service attacks. * * @param requestHeaderSize Max header size in bytes */ public void setRequestHeaderSize(int requestHeaderSize) { _requestHeaderSize = requestHeaderSize; } /* ------------------------------------------------------------ */ /** * Set the maximum size of a response header. * * <p>Larger headers will allow for more and/or larger cookies and longer HTTP headers (eg for * redirection). However, larger headers will also consume more memory. * * @param responseHeaderSize Response header size in bytes. */ public void setResponseHeaderSize(int responseHeaderSize) { _responseHeaderSize = responseHeaderSize; } /* ------------------------------------------------------------ */ /** * Set the header field cache size. * * @param headerCacheSize The size in bytes of the header field cache. */ public void setHeaderCacheSize(int headerCacheSize) { _headerCacheSize = headerCacheSize; } /* ------------------------------------------------------------ */ /** * Set the TCP/IP port used for CONFIDENTIAL and INTEGRAL redirections. * * @param confidentialPort */ public void setSecurePort(int confidentialPort) { _securePort = confidentialPort; } /* ------------------------------------------------------------ */ /** * Set the URI scheme used for CONFIDENTIAL and INTEGRAL redirections. * * @param confidentialScheme A string like"https" */ public void setSecureScheme(String confidentialScheme) { _secureScheme = confidentialScheme; } @Override public String toString() { return String.format( "%s@%x{%d,%d/%d,%s://:%d,%s}", this.getClass().getSimpleName(), hashCode(), _outputBufferSize, _requestHeaderSize, _responseHeaderSize, _secureScheme, _securePort, _customizers); } }
@Override public URI getURI() { String scheme = isSecure() ? HttpScheme.HTTPS.asString() : HttpScheme.HTTP.asString(); return URI.create(new Origin(scheme, getAddress()).asString()); }
@Override public String encodeURL(String url) { final Request request = _channel.getRequest(); SessionManager sessionManager = request.getSessionManager(); if (sessionManager == null) return url; HttpURI uri = null; if (sessionManager.isCheckingRemoteSessionIdEncoding() && URIUtil.hasScheme(url)) { uri = new HttpURI(url); String path = uri.getPath(); path = (path == null ? "" : path); int port = uri.getPort(); if (port < 0) port = HttpScheme.HTTPS.asString().equalsIgnoreCase(uri.getScheme()) ? 443 : 80; if (!request.getServerName().equalsIgnoreCase(uri.getHost()) || request.getServerPort() != port || !path.startsWith( request .getContextPath())) // TODO the root context path is "", with which every non null // string starts return url; } String sessionURLPrefix = sessionManager.getSessionIdPathParameterNamePrefix(); if (sessionURLPrefix == null) return url; if (url == null) return null; // should not encode if cookies in evidence if (request.isRequestedSessionIdFromCookie()) { int prefix = url.indexOf(sessionURLPrefix); if (prefix != -1) { int suffix = url.indexOf("?", prefix); if (suffix < 0) suffix = url.indexOf("#", prefix); if (suffix <= prefix) return url.substring(0, prefix); return url.substring(0, prefix) + url.substring(suffix); } return url; } // get session; HttpSession session = request.getSession(false); // no session if (session == null) return url; // invalid session if (!sessionManager.isValid(session)) return url; String id = sessionManager.getNodeId(session); if (uri == null) uri = new HttpURI(url); // Already encoded int prefix = url.indexOf(sessionURLPrefix); if (prefix != -1) { int suffix = url.indexOf("?", prefix); if (suffix < 0) suffix = url.indexOf("#", prefix); if (suffix <= prefix) return url.substring(0, prefix + sessionURLPrefix.length()) + id; return url.substring(0, prefix + sessionURLPrefix.length()) + id + url.substring(suffix); } // edit the session int suffix = url.indexOf('?'); if (suffix < 0) suffix = url.indexOf('#'); if (suffix < 0) { return url + ((HttpScheme.HTTPS.is(uri.getScheme()) || HttpScheme.HTTP.is(uri.getScheme())) && uri.getPath() == null ? "/" : "") + // if no path, insert the root path sessionURLPrefix + id; } return url.substring(0, suffix) + ((HttpScheme.HTTPS.is(uri.getScheme()) || HttpScheme.HTTP.is(uri.getScheme())) && uri.getPath() == null ? "/" : "") + // if no path so insert the root path sessionURLPrefix + id + url.substring(suffix); }