package io.embrace.android.embracesdk.internal.network.http;
import static io.embrace.android.embracesdk.config.behavior.NetworkSpanForwardingBehavior.TRACEPARENT_HEADER_NAME;
import android.annotation.TargetApi;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.security.Permission;
import java.security.Principal;
import java.security.cert.Certificate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.zip.GZIPInputStream;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSocketFactory;
import io.embrace.android.embracesdk.Embrace;
import io.embrace.android.embracesdk.InternalApi;
import io.embrace.android.embracesdk.logging.InternalStaticEmbraceLogger;
import io.embrace.android.embracesdk.network.EmbraceNetworkRequest;
import io.embrace.android.embracesdk.network.http.HttpMethod;
import io.embrace.android.embracesdk.utils.exceptions.function.CheckedSupplier;
import kotlin.jvm.functions.Function0;
/**
* Wraps {@link HttpURLConnection} to log network calls to Embrace. The wrapper also wraps the
* InputStream to get an accurate count of bytes received if a Content-Length is not provided by
* the server.
*
* The wrapper handles gzip decompression itself and strips the {@code Content-Length} and
* {@code Content-Encoding} headers. Typically this is handled transparently by
* {@link HttpURLConnection} but would prevent us from accessing the {@code Content-Length}.
*
* Network logging currently does not follow redirects. The duration is logged from initiation of
* the network call (upon invocation of any method which would initiate the network call), to the
* retrieval of the response.
*
* As network calls are initiated lazily, we log the network call prior to the calling of any
* wrapped method which would result in the network call actually being executed, and store a
* flag to prevent duplication of calls.
*/
@InternalApi
class EmbraceUrlConnectionDelegate implements EmbraceHttpsUrlConnection {
/**
* The content encoding HTTP header.
*/
private static final String CONTENT_ENCODING = "Content-Encoding";
/**
* The content length HTTP header.
*/
private static final String CONTENT_LENGTH = "Content-Length";
/**
* Reference to the wrapped connection.
*/
private final T connection;
/**
* The time at which the connection was created.
*/
private final long createdTime;
/**
* Whether transparent gzip compression is enabled.
*/
private final boolean enableWrapIoStreams;
/**
* Reference to the SDK that is mockable and fakeable in tests
*/
private final Embrace embrace;
@NonNull
private final String callId;
/**
* A reference to the output stream wrapped in a counter, so we can determine the bytes sent.
*/
private volatile CountingOutputStream outputStream;
/**
* Whether the network call has already been logged, to prevent duplication.
*/
private volatile boolean didLogNetworkCall = false;
/**
* The time at which the network call ended.
*/
private volatile Long endTime;
/**
* The time at which the network call was initiated.
*/
private volatile Long startTime;
/**
* The trace id specified for the request
*/
private volatile String traceId;
/**
* The request headers captured from the http connection.
*/
private volatile HashMap requestHeaders;
/**
* Indicates if the request throws a IOException
*/
private volatile Exception inputStreamAccessException;
private volatile Exception lastConnectionAccessException;
private final AtomicLong responseSize = new AtomicLong(-1);
private final AtomicInteger responseCode = new AtomicInteger(0);
private final AtomicReference