OSDN Git Service

Captive portal: better detect empty responses
authorHugo Benichi <hugobenichi@google.com>
Wed, 11 Jan 2017 07:23:26 +0000 (16:23 +0900)
committerHugo Benichi <hugobenichi@google.com>
Thu, 16 Feb 2017 03:31:30 +0000 (12:31 +0900)
The captive portal detection logic treats empty http responses with a
Content-Length of 0 as not coming from a portal.

However when the Content-Length is missing from the response header, the
empty response is not detected as such and is classified as a captive
portal answer.

When this happens for the http probe, the portal detection logic will
short circuit the detection and wrongly report a portal. The system
validates the network in such conditions only if the https probe
returns a successful connection faster than the http probe.

This patch attempts to better detect empty responses by trying to read
the first byte from the response body when the Content-Length is missing
for 200 responses.

Test: build, flashed + manual tests.
Bug: 33498325

(cherry picked from commit cb4aa4d412c7940386df9b8dd681e0d2efebfd1d)

Change-Id: Ibb9914cba72a4dab3ae76746d8889bbf083be812

services/core/java/com/android/server/connectivity/NetworkMonitor.java

index 9ffe2b7..c40780e 100644 (file)
@@ -809,19 +809,26 @@ public class NetworkMonitor extends StateMachine {
             // portal.  If it is considered a captive portal, a different sign-in URL
             // is needed (i.e. can't browse a 204).  This could be the result of an HTTP
             // proxy server.
-
-            // Consider 200 response with "Content-length=0" to not be a captive portal.
-            // There's no point in considering this a captive portal as the user cannot
-            // sign-in to an empty page.  Probably the result of a broken transparent proxy.
-            // See http://b/9972012.
-            if (httpResponseCode == 200 && urlConnection.getContentLength() == 0) {
-                validationLog("Empty 200 response interpreted as 204 response.");
-                httpResponseCode = 204;
-            }
-
-            if (httpResponseCode == 200 && probeType == ValidationProbeEvent.PROBE_PAC) {
-                validationLog("PAC fetch 200 response interpreted as 204 response.");
-                httpResponseCode = 204;
+            if (httpResponseCode == 200) {
+                if (probeType == ValidationProbeEvent.PROBE_PAC) {
+                    validationLog("PAC fetch 200 response interpreted as 204 response.");
+                    httpResponseCode = 204;
+                } else if (urlConnection.getContentLengthLong() == 0) {
+                    // Consider 200 response with "Content-length=0" to not be a captive portal.
+                    // There's no point in considering this a captive portal as the user cannot
+                    // sign-in to an empty page. Probably the result of a broken transparent proxy.
+                    // See http://b/9972012.
+                    validationLog(
+                        "200 response with Content-length=0 interpreted as 204 response.");
+                    httpResponseCode = 204;
+                } else if (urlConnection.getContentLengthLong() == -1) {
+                    // When no Content-length (default value == -1), attempt to read a byte from the
+                    // response. Do not use available() as it is unreliable. See http://b/33498325.
+                    if (urlConnection.getInputStream().read() == -1) {
+                        validationLog("Empty 200 response interpreted as 204 response.");
+                        httpResponseCode = 204;
+                    }
+                }
             }
         } catch (IOException e) {
             validationLog("Probably not a portal: exception " + e);