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 isSuccessCode(mHttpResponseCode); 107 } 108 isPortal()109 public boolean isPortal() { 110 return isPortalCode(mHttpResponseCode); 111 } 112 isSuccessCode(int responseCode)113 private static boolean isSuccessCode(int responseCode) { 114 return responseCode == SUCCESS_CODE; 115 } 116 117 /** 118 * @return Whether the specified HTTP return code indicates a captive portal. 119 */ isPortalCode(int responseCode)120 public static boolean isPortalCode(int responseCode) { 121 return !isSuccessCode(responseCode) && (responseCode >= 200) && (responseCode <= 399); 122 } 123 isFailed()124 public boolean isFailed() { 125 return !isSuccessful() && !isPortal(); 126 } 127 isPartialConnectivity()128 public boolean isPartialConnectivity() { 129 return mHttpResponseCode == PARTIAL_CODE; 130 } 131 isDnsPrivateIpResponse()132 public boolean isDnsPrivateIpResponse() { 133 return mHttpResponseCode == DNS_PRIVATE_IP_RESPONSE_CODE; 134 } 135 136 /** 137 * Make a failed {@code this} for either HTTPS or HTTP determined by {@param isHttps}. 138 * @param probeType probe type of the result. 139 * @return a failed {@link CaptivePortalProbeResult} 140 */ failed(@robeType int probeType)141 public static CaptivePortalProbeResult failed(@ProbeType int probeType) { 142 return new CaptivePortalProbeResult(FAILED_CODE, probeType); 143 } 144 145 /** 146 * Make a success {@code this} for either HTTPS or HTTP determined by {@param isHttps}. 147 * @param probeType probe type of the result. 148 * @return a success {@link CaptivePortalProbeResult} 149 */ success(@robeType int probeType)150 public static CaptivePortalProbeResult success(@ProbeType int probeType) { 151 return new CaptivePortalProbeResult(SUCCESS_CODE, probeType); 152 } 153 154 /** 155 * As {@code this} is the result of calling isCaptivePortal(), the result may be determined from 156 * one or more probes depending on the configuration of detection probes. Return if HTTPS probe 157 * is one of the probes that concludes it. 158 */ isConcludedFromHttps()159 public boolean isConcludedFromHttps() { 160 return (probeType & (1 << PROBE_HTTPS)) != 0; 161 } 162 163 /** 164 * As {@code this} is the result of calling isCaptivePortal(), the result may be determined from 165 * one or more probes depending on the configuration of detection probes. Return if HTTP probe 166 * is one of the probes that concludes it. 167 */ isConcludedFromHttp()168 public boolean isConcludedFromHttp() { 169 return (probeType & (1 << PROBE_HTTP)) != 0; 170 } 171 } 172