Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3794a838 authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 6210127 from 8a8b36c7 to rvc-release

Change-Id: I1a8a140ade2ba1d84f38bc5ab77114740161ade3
parents 10b918f2 8a8b36c7
Loading
Loading
Loading
Loading
+65 −9
Original line number Diff line number Diff line
@@ -153,11 +153,15 @@ import com.android.networkstack.netlink.TcpSocketTracker;
import com.android.networkstack.util.DnsUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -171,6 +175,8 @@ import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * {@hide}
@@ -1810,15 +1816,10 @@ public class NetworkMonitor extends StateMachine {
        final int oldTag = TrafficStats.getAndSetThreadStatsTag(
                TrafficStatsConstants.TAG_SYSTEM_PROBE);
        try {
            urlConnection = (HttpURLConnection) mCleartextDnsNetwork.openConnection(url);
            urlConnection.setInstanceFollowRedirects(probeType == ValidationProbeEvent.PROBE_PAC);
            urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
            urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
            urlConnection.setRequestProperty("Connection", "close");
            urlConnection.setUseCaches(false);
            if (mCaptivePortalUserAgent != null) {
                urlConnection.setRequestProperty("User-Agent", mCaptivePortalUserAgent);
            }
            // Follow redirects for PAC probes as such probes verify connectivity by fetching the
            // PAC proxy file, which may be configured behind a redirect.
            final boolean followRedirect = probeType == ValidationProbeEvent.PROBE_PAC;
            urlConnection = makeProbeConnection(url, followRedirect);
            // cannot read request header after connection
            String requestHeader = urlConnection.getRequestProperties().toString();

@@ -1886,6 +1887,61 @@ public class NetworkMonitor extends StateMachine {
        }
    }

    private HttpURLConnection makeProbeConnection(URL url, boolean followRedirects)
            throws IOException {
        final HttpURLConnection conn = (HttpURLConnection) mCleartextDnsNetwork.openConnection(url);
        conn.setInstanceFollowRedirects(followRedirects);
        conn.setConnectTimeout(SOCKET_TIMEOUT_MS);
        conn.setReadTimeout(SOCKET_TIMEOUT_MS);
        conn.setRequestProperty("Connection", "close");
        conn.setUseCaches(false);
        if (mCaptivePortalUserAgent != null) {
            conn.setRequestProperty("User-Agent", mCaptivePortalUserAgent);
        }
        return conn;
    }

    @VisibleForTesting
    @NonNull
    protected static String readAsString(InputStream is, int maxLength, Charset charset)
            throws IOException {
        final InputStreamReader reader = new InputStreamReader(is, charset);
        final char[] buffer = new char[1000];
        final StringBuilder builder = new StringBuilder();
        int totalReadLength = 0;
        while (totalReadLength < maxLength) {
            final int availableLength = Math.min(maxLength - totalReadLength, buffer.length);
            final int currentLength = reader.read(buffer, 0, availableLength);
            if (currentLength < 0) break; // EOF

            totalReadLength += currentLength;
            builder.append(buffer, 0, currentLength);
        }
        return builder.toString();
    }

    /**
     * Attempt to extract the {@link Charset} of the response from its Content-Type header.
     *
     * <p>If the {@link Charset} cannot be extracted, UTF-8 is returned by default.
     */
    @VisibleForTesting
    @NonNull
    protected static Charset extractCharset(@Nullable String contentTypeHeader) {
        if (contentTypeHeader == null) return StandardCharsets.UTF_8;
        // See format in https://tools.ietf.org/html/rfc7231#section-3.1.1.1
        final Pattern charsetPattern = Pattern.compile("; *charset=\"?([^ ;\"]+)\"?",
                Pattern.CASE_INSENSITIVE);
        final Matcher matcher = charsetPattern.matcher(contentTypeHeader);
        if (!matcher.find()) return StandardCharsets.UTF_8;

        try {
            return Charset.forName(matcher.group(1));
        } catch (IllegalArgumentException e) {
            return StandardCharsets.UTF_8;
        }
    }

    private CaptivePortalProbeResult sendParallelHttpProbes(
            ProxyInfo proxy, URL httpsUrl, URL httpUrl) {
        // Number of probes to wait for. If a probe completes with a conclusive answer
+46 −1
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import static com.android.networkstack.apishim.ConstantsShim.KEY_NETWORK_VALIDAT
import static com.android.networkstack.apishim.ConstantsShim.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS;
import static com.android.networkstack.apishim.ConstantsShim.KEY_TCP_PACKET_FAIL_RATE;
import static com.android.networkstack.util.DnsUtils.PRIVATE_DNS_PROBE_HOST_SUFFIX;
import static com.android.server.connectivity.NetworkMonitor.extractCharset;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -137,11 +138,14 @@ import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -450,7 +454,6 @@ public class NetworkMonitorTest {
    @After
    public void tearDown() {
        mFakeDns.clearAll();
        assertTrue(mCreatedNetworkMonitors.size() > 0);
        // Make a local copy of mCreatedNetworkMonitors because during the iteration below,
        // WrappedNetworkMonitor#onQuitting will delete elements from it on the handler threads.
        WrappedNetworkMonitor[] networkMonitors = mCreatedNetworkMonitors.toArray(
@@ -1345,6 +1348,48 @@ public class NetworkMonitorTest {
                NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS));
    }

    @Test
    public void testExtractCharset() {
        assertEquals(StandardCharsets.UTF_8, extractCharset(null));
        assertEquals(StandardCharsets.UTF_8, extractCharset("text/html;charset=utf-8"));
        assertEquals(StandardCharsets.UTF_8, extractCharset("text/html;charset=UtF-8"));
        assertEquals(StandardCharsets.UTF_8, extractCharset("text/html; Charset=\"utf-8\""));
        assertEquals(StandardCharsets.UTF_8, extractCharset("image/png"));
        assertEquals(StandardCharsets.UTF_8, extractCharset("Text/HTML;"));
        assertEquals(StandardCharsets.UTF_8, extractCharset("multipart/form-data; boundary=-aa*-"));
        assertEquals(StandardCharsets.UTF_8, extractCharset("text/plain;something=else"));
        assertEquals(StandardCharsets.UTF_8, extractCharset("text/plain;charset=ImNotACharset"));

        assertEquals(StandardCharsets.ISO_8859_1, extractCharset("text/plain; CharSeT=ISO-8859-1"));
        assertEquals(Charset.forName("Shift_JIS"), extractCharset("text/plain;charset=Shift_JIS"));
        assertEquals(Charset.forName("Windows-1251"), extractCharset(
                "text/plain;charset=Windows-1251 ; somethingelse"));
    }

    @Test
    public void testReadAsString() throws IOException {
        final String repeatedString = "1aテスト-?";
        // Infinite stream repeating characters
        class TestInputStream extends InputStream {
            private final byte[] mBytes = repeatedString.getBytes(StandardCharsets.UTF_8);
            private int mPosition = -1;

            @Override
            public int read() {
                mPosition = (mPosition + 1) % mBytes.length;
                return mBytes[mPosition];
            }
        }

        final String readString = NetworkMonitor.readAsString(new TestInputStream(),
                1500 /* maxLength */, StandardCharsets.UTF_8);

        assertEquals(1500, readString.length());
        for (int i = 0; i < readString.length(); i++) {
            assertEquals(repeatedString.charAt(i % repeatedString.length()), readString.charAt(i));
        }
    }

    private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
        for (int i = 0; i < count; i++) {
            wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(