<commit_before>/*
 * Copyright (c) 2011-Present VMware, Inc. or its affiliates, All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package reactor.netty.tcp;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import javax.annotation.Nullable;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.proxy.HttpProxyHandler;
import io.netty.handler.proxy.ProxyHandler;
import io.netty.handler.proxy.Socks4ProxyHandler;
import io.netty.handler.proxy.Socks5ProxyHandler;
import reactor.netty.ConnectionObserver;
import io.netty.util.internal.StringUtil;
import reactor.netty.NettyPipeline;
import reactor.netty.channel.BootstrapHandlers;

import static reactor.netty.tcp.ProxyProvider.Build.ALWAYS_PROXY;

/**
 * Proxy configuration
 *
 * @author <NAME>
 */
public final class ProxyProvider {

	/**
	 * Creates a builder for {@link ProxyProvider ProxyProvider}
	 *
	 * @return a new ProxyProvider builder
	 */
	public static ProxyProvider.TypeSpec builder() {
		return new ProxyProvider.Build();
	}

	/**
	 * Find Proxy support in the given client bootstrap
	 *
	 * @param b a bootstrap to search
	 *
	 * @return any {@link ProxyProvider} found or null
	 */
	@Nullable
	public static ProxyProvider findProxySupport(Bootstrap b) {
		ProxyProvider.DeferredProxySupport proxy =
				BootstrapHandlers.findConfiguration(ProxyProvider.DeferredProxySupport.class, b.config().handler());

		if (proxy == null) {
			return null;
		}
		return proxy.proxyProvider;
	}

	final String username;
	final Function<? super String, ? extends String> password;
	final Supplier<? extends InetSocketAddress> address;
	final Predicate<SocketAddress> nonProxyHostPredicate;
	final Supplier<? extends HttpHeaders> httpHeaders;
	final Proxy type;
	final long connectTimeoutMillis;

	ProxyProvider(ProxyProvider.Build builder) {
		this.username = builder.username;
		this.password = <PASSWORD>;
		this.nonProxyHostPredicate = builder.nonProxyHostPredicate;
		if (Objects.isNull(builder.address)) {
			this.address = () -> InetSocketAddressUtil.createResolved(builder.host, builder.port);
		}
		else {
			this.address = builder.address;
		}
		this.httpHeaders = builder.httpHeaders;
		this.type = builder.type;
		this.connectTimeoutMillis = builder.connectTimeoutMillis;
	}

	/**
	 * The proxy type
	 *
	 * @return The proxy type
	 */
	public final Proxy getType() {
		return this.type;
	}

	/**
	 * The supplier for the address to connect to.
	 *
	 * @return The supplier for the address to connect to.
	 */
	public final Supplier<? extends InetSocketAddress> getAddress() {
		return this.address;
	}

	/**
	 * Regular expression (<code>using java.util.regex</code>) for a configured
	 * list of hosts that should be reached directly, bypassing the proxy.
	 *
	 * @return Regular expression (<code>using java.util.regex</code>) for
	 * a configured list of hosts that should be reached directly, bypassing the
	 * proxy.
	 * @deprecated as of 0.9.10. Use {@link #getNonProxyHostsPredicate()}. This method will be removed in version 1.0.0.
	 */
	@Nullable
	@Deprecated
	public final Pattern getNonProxyHosts() {
		if (nonProxyHostPredicate instanceof RegexShouldProxyPredicate) {
			return ((RegexShouldProxyPredicate) nonProxyHostPredicate).pattern;
		}
		else {
			return null;
		}
	}

	/**
	 * A predicate {@link Predicate} on {@link SocketAddress} that returns true when the provided address should be
	 * reached directly, bypassing the proxy
	 *
	 * @return The predicate {@link Predicate} to test the incoming {@link SocketAddress} if it should be reached
	 * directly, bypassing the proxy
	 * @since 0.9.10
	 */
	public final Predicate<SocketAddress> getNonProxyHostsPredicate() {
		return this.nonProxyHostPredicate;
	}

	/**
	 * Return a new eventual {@link ProxyHandler}
	 *
	 * @return a new eventual {@link ProxyHandler}
	 */
	public final ProxyHandler newProxyHandler() {
		InetSocketAddress proxyAddr = this.address.get();
		String username = this.username;
		String password = Objects.nonNull(username) && Objects.nonNull(this.password) ?
				this.password.apply(username) : null;

		final boolean b = Objects.nonNull(username) && Objects.nonNull(password);
		final ProxyHandler proxyHandler;
		switch (this.type) {
			case HTTP:<commit_msg>Remove redundant code<commit_after>/*
 * Copyright (c) 2011-Present VMware, Inc. or its affiliates, All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package reactor.netty.tcp;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import javax.annotation.Nullable;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.proxy.HttpProxyHandler;
import io.netty.handler.proxy.ProxyHandler;
import io.netty.handler.proxy.Socks4ProxyHandler;
import io.netty.handler.proxy.Socks5ProxyHandler;
import reactor.netty.ConnectionObserver;
import io.netty.util.internal.StringUtil;
import reactor.netty.NettyPipeline;
import reactor.netty.channel.BootstrapHandlers;

import static reactor.netty.tcp.ProxyProvider.Build.ALWAYS_PROXY;

/**
 * Proxy configuration
 *
 * @author <NAME>
 */
public final class ProxyProvider {

	/**
	 * Creates a builder for {@link ProxyProvider ProxyProvider}
	 *
	 * @return a new ProxyProvider builder
	 */
	public static ProxyProvider.TypeSpec builder() {
		return new ProxyProvider.Build();
	}

	/**
	 * Find Proxy support in the given client bootstrap
	 *
	 * @param b a bootstrap to search
	 *
	 * @return any {@link ProxyProvider} found or null
	 */
	@Nullable
	public static ProxyProvider findProxySupport(Bootstrap b) {
		ProxyProvider.DeferredProxySupport proxy =
				BootstrapHandlers.findConfiguration(ProxyProvider.DeferredProxySupport.class, b.config().handler());

		if (proxy == null) {
			return null;
		}
		return proxy.proxyProvider;
	}

	final String username;
	final Function<? super String, ? extends String> password;
	final Supplier<? extends InetSocketAddress> address;
	final Predicate<SocketAddress> nonProxyHostPredicate;
	final Supplier<? extends HttpHeaders> httpHeaders;
	final Proxy type;
	final long connectTimeoutMillis;

	ProxyProvider(ProxyProvider.Build builder) {
		this.username = builder.username;
		this.password = <PASSWORD>;
		this.nonProxyHostPredicate = builder.nonProxyHostPredicate;
		if (Objects.isNull(builder.address)) {
			this.address = () -> InetSocketAddressUtil.createResolved(builder.host, builder.port);
		}
		else {
			this.address = builder.address;
		}
		this.httpHeaders = builder.httpHeaders;
		this.type = builder.type;
		this.connectTimeoutMillis = builder.connectTimeoutMillis;
	}

	/**
	 * The proxy type
	 *
	 * @return The proxy type
	 */
	public final Proxy getType() {
		return this.type;
	}

	/**
	 * The supplier for the address to connect to.
	 *
	 * @return The supplier for the address to connect to.
	 */
	public final Supplier<? extends InetSocketAddress> getAddress() {
		return this.address;
	}

	/**
	 * Regular expression (<code>using java.util.regex</code>) for a configured
	 * list of hosts that should be reached directly, bypassing the proxy.
	 *
	 * @return Regular expression (<code>using java.util.regex</code>) for
	 * a configured list of hosts that should be reached directly, bypassing the
	 * proxy.
	 * @deprecated as of 0.9.10. Use {@link #getNonProxyHostsPredicate()}. This method will be removed in version 1.0.0.
	 */
	@Nullable
	@Deprecated
	public final Pattern getNonProxyHosts() {
		if (nonProxyHostPredicate instanceof RegexShouldProxyPredicate) {
			return ((RegexShouldProxyPredicate) nonProxyHostPredicate).pattern;
		}
		else {
			return null;
		}
	}

	/**
	 * A predicate {@link Predicate} on {@link SocketAddress} that returns true when the provided address should be
	 * reached directly, bypassing the proxy
	 *
	 * @return The predicate {@link Predicate} to test the incoming {@link SocketAddress} if it should be reached
	 * directly, bypassing the proxy
	 * @since 0.9.10
	 */
	public final Predicate<SocketAddress> getNonProxyHostsPredicate() {
		return this.nonProxyHostPredicate;
	}

	/**
	 * Return a new eventual {@link ProxyHandler}
	 *
	 * @return a new eventual {@link ProxyHandler}
	 */
	public final ProxyHandler newProxyHandler() {
		InetSocketAddress proxyAddr = this.address.get();

		final boolean b = Objects.nonNull(username) && Objects.nonNull(password);

		String username = this.username;
		String password = b ? <PASSWORD>(username) : <PASSWORD>;

		final ProxyHandler proxyHandler;
		switch (this.type) {
			case HTTP:
{'fraction_non_alphanumeric': 0.0977501196744854, 'fraction_numerical': 0.004021062709430349, 'mean_word_length': 4.390092879256966, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 31, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6809973', 'n_tokens_mistral': 3210, 'n_tokens_neox': 2966, 'n_words': 908}