1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.captiveportal;
18 
19 import static android.net.metrics.ValidationProbeEvent.PROBE_HTTP;
20 import static android.net.metrics.ValidationProbeEvent.PROBE_HTTPS;
21 
22 import androidx.annotation.IntDef;
23 import androidx.annotation.NonNull;
24 import androidx.annotation.Nullable;
25 
26 import java.lang.annotation.Retention;
27 import java.lang.annotation.RetentionPolicy;
28 /**
29  * Result of calling isCaptivePortal().
30  * @hide
31  */
32 public class CaptivePortalProbeResult {
33     public static final int SUCCESS_CODE = 204;
34     public static final int FAILED_CODE = 599;
35     public static final int PORTAL_CODE = 302;
36     // Set partial connectivity http response code to -1 to prevent conflict with the other http
37     // response codes. Besides the default http response code of probe result is set as 599 in
38     // NetworkMonitor#sendParallelHttpProbes(), so response code will be set as -1 only when
39     // NetworkMonitor detects partial connectivity.
40     /**
41      * @hide
42      */
43     public static final int PARTIAL_CODE = -1;
44 
45     // DNS response with private IP on the probe URL suggests that the network, especially Wi-Fi
46     // network is not connected to the Internet. This code represents the result of a single probe,
47     // for correct logging of the probe results. The result of the whole evaluation would typically
48     // be FAILED if one of the probes returns this status.
49     // This logic is only used if the config_force_dns_probe_private_ip_no_internet flag is set.
50     public static final int DNS_PRIVATE_IP_RESPONSE_CODE = -2;
51     // The private IP logic only applies to the HTTP probe.
52     public static final CaptivePortalProbeResult PRIVATE_IP =
53             new CaptivePortalProbeResult(DNS_PRIVATE_IP_RESPONSE_CODE, 1 << PROBE_HTTP);
54     // Partial connectivity should be concluded from both HTTP and HTTPS probes.
55     @NonNull
56     public static final CaptivePortalProbeResult PARTIAL = new CaptivePortalProbeResult(
57             PARTIAL_CODE, 1 << PROBE_HTTP | 1 << PROBE_HTTPS);
58     // Probe type that is used for unspecified probe result.
59     public static final int PROBE_UNKNOWN = 0;
60 
61     final int mHttpResponseCode;  // HTTP response code returned from Internet probe.
62     @Nullable
63     public final String redirectUrl;      // Redirect destination returned from Internet probe.
64     @Nullable
65     public final String detectUrl;        // URL where a 204 response code indicates
66                                           // captive portal has been appeased.
67     @Nullable
68     public final CaptivePortalProbeSpec probeSpec;
69 
70     // Indicate what kind of probe this is. This is a bitmask constructed by
71     // bitwise-or-ing(i.e. {@code |}) the {@code ValidationProbeEvent.PROBE_HTTP} or
72     // {@code ValidationProbeEvent.PROBE_HTTPS} values. Set it as {@code PROBE_UNKNOWN} if the probe
73     // type is unspecified.
74     @ProbeType
75     public final int probeType;
76 
77     @IntDef(value = {
78         PROBE_UNKNOWN,
79         1 << PROBE_HTTP,
80         1 << PROBE_HTTPS,
81     })
82     @Retention(RetentionPolicy.SOURCE)
83     public @interface ProbeType {
84     }
85 
CaptivePortalProbeResult(int httpResponseCode, @ProbeType int probeType)86     public CaptivePortalProbeResult(int httpResponseCode, @ProbeType int probeType) {
87         this(httpResponseCode, null, null, null, probeType);
88     }
89 
CaptivePortalProbeResult(int httpResponseCode, @Nullable String redirectUrl, @Nullable String detectUrl, @ProbeType int probeType)90     public CaptivePortalProbeResult(int httpResponseCode, @Nullable String redirectUrl,
91             @Nullable String detectUrl, @ProbeType int probeType) {
92         this(httpResponseCode, redirectUrl, detectUrl, null, probeType);
93     }
94 
CaptivePortalProbeResult(int httpResponseCode, @Nullable String redirectUrl, @Nullable String detectUrl, @Nullable CaptivePortalProbeSpec probeSpec, @ProbeType int probeType)95     public CaptivePortalProbeResult(int httpResponseCode, @Nullable String redirectUrl,
96             @Nullable String detectUrl, @Nullable CaptivePortalProbeSpec probeSpec,
97             @ProbeType int probeType) {
98         mHttpResponseCode = httpResponseCode;
99         this.redirectUrl = redirectUrl;
100         this.detectUrl = detectUrl;
101         this.probeSpec = probeSpec;
102         this.probeType = probeType;
103     }
104 
isSuccessful()105     public boolean isSuccessful() {
106         return mHttpResponseCode == SUCCESS_CODE;
107     }
108 
isPortal()109     public boolean isPortal() {
110         return !isSuccessful() && (mHttpResponseCode >= 200) && (mHttpResponseCode <= 399);
111     }
112 
isFailed()113     public boolean isFailed() {
114         return !isSuccessful() && !isPortal();
115     }
116 
isPartialConnectivity()117     public boolean isPartialConnectivity() {
118         return mHttpResponseCode == PARTIAL_CODE;
119     }
120 
isDnsPrivateIpResponse()121     public boolean isDnsPrivateIpResponse() {
122         return mHttpResponseCode == DNS_PRIVATE_IP_RESPONSE_CODE;
123     }
124 
125     /**
126      *  Make a failed {@code this} for either HTTPS or HTTP determined by {@param isHttps}.
127      *  @param probeType probe type of the result.
128      *  @return a failed {@link CaptivePortalProbeResult}
129      */
failed(@robeType int probeType)130     public static CaptivePortalProbeResult failed(@ProbeType int probeType) {
131         return new CaptivePortalProbeResult(FAILED_CODE, probeType);
132     }
133 
134     /**
135      *  Make a success {@code this} for either HTTPS or HTTP determined by {@param isHttps}.
136      *  @param probeType probe type of the result.
137      *  @return a success {@link CaptivePortalProbeResult}
138      */
success(@robeType int probeType)139     public static CaptivePortalProbeResult success(@ProbeType int probeType) {
140         return new CaptivePortalProbeResult(SUCCESS_CODE, probeType);
141     }
142 
143     /**
144      * As {@code this} is the result of calling isCaptivePortal(), the result may be determined from
145      * one or more probes depending on the configuration of detection probes. Return if HTTPS probe
146      * is one of the probes that concludes it.
147      */
isConcludedFromHttps()148     public boolean isConcludedFromHttps() {
149         return (probeType & (1 << PROBE_HTTPS)) != 0;
150     }
151 
152     /**
153      * As {@code this} is the result of calling isCaptivePortal(), the result may be determined from
154      * one or more probes depending on the configuration of detection probes. Return if HTTP probe
155      * is one of the probes that concludes it.
156      */
isConcludedFromHttp()157     public boolean isConcludedFromHttp() {
158         return (probeType & (1 << PROBE_HTTP)) != 0;
159     }
160 }
161