# 값 타입의 컴팩트 생성자가 하는 검사 전부
22:  public WebPushSubscriptionValue {
23:    Objects.requireNonNull(endpoint, "endpoint");
24:    Objects.requireNonNull(p256dh, "p256dh");
25:    Objects.requireNonNull(authSecret, "authSecret");
26:    Objects.requireNonNull(vapidKeyId, "vapidKeyId");
27:    if (!isSecureOrLoopback(endpoint)) {
28:      throw new IllegalArgumentException("endpoint must be https outside the loopback interface");
29:    }
30:    if (p256dh.length != P256DH_LENGTH) {
31:      throw new IllegalArgumentException("p256dh must be an uncompressed P-256 point");
32:    }
33:    if (authSecret.length != AUTH_SECRET_LENGTH) {
34:      throw new IllegalArgumentException("authSecret must be 16 bytes");
35:    }
36:    if (vapidKeyId.isBlank()) {
37:      throw new IllegalArgumentException("vapidKeyId");
38:    }
# 다섯째 검사의 구현 — 같은 파일 안의 private 메서드
50:  private static boolean isSecureOrLoopback(java.net.URI endpoint) {
51:    String scheme = endpoint.getScheme() == null ? "" : endpoint.getScheme();
52:    if ("https".equalsIgnoreCase(scheme)) {
53:      return true;
54:    }
55:    String host =
56:        endpoint.getHost() == null ? "" : endpoint.getHost().toLowerCase(java.util.Locale.ROOT);
57:    return "http".equalsIgnoreCase(scheme)
58:        && ("127.0.0.1".equals(host) || "::1".equals(host) || "localhost".equals(host));
59:  }

# 그 private 사본이 베낀 원본. 같은 모듈의 공개 함수다.
24:  public static URI requireSecureOrLoopback(URI endpoint, String name) {
25:    Objects.requireNonNull(endpoint, name);
26:    String scheme =
27:        endpoint.getScheme() == null ? "" : endpoint.getScheme().toLowerCase(Locale.ROOT);
28:    if ("https".equals(scheme)) {
29:      return endpoint;
30:    }
31:    String host = endpoint.getHost() == null ? "" : endpoint.getHost().toLowerCase(Locale.ROOT);
32:    if ("http".equals(scheme) && LOOPBACK_HOSTS.contains(host)) {
33:      return endpoint;
34:    }
35:    throw new IllegalArgumentException(name + " must use https outside the loopback interface");

# 같은 파일의 다른 공개 함수가 자기가 누구를 위한 것인지 적는다
47:   * <p>{@link #requireSecureOrLoopback} checks the scheme and nothing else, so any HTTPS URL was
48:   * accepted — including {@code https://169.254.169.254/}, the cloud metadata service, and any RFC
49:   * 1918 address. Web Push endpoints and webhook targets are supplied by clients, which makes this
50:   * a server-side request forgery primitive: the platform will happily fetch an internal address
51:   * and, for a webhook, deliver the message body there.
# 그 함수가 실제로 하는 검사
65:  public static URI requireExternallyRoutable(URI endpoint, String name, boolean allowLoopback) {
66:    Objects.requireNonNull(endpoint, name);
67:    requireSecureOrLoopback(endpoint, name);
68:    if (endpoint.getUserInfo() != null) {
71:      throw new IllegalArgumentException(name + " must not carry userinfo");
72:    }
73:    String host = endpoint.getHost();
74:    if (host == null || host.isBlank()) {
75:      throw new IllegalArgumentException(name + " has no host");
76:    }
77:    if (allowLoopback && isLoopback(endpoint)) {
78:      return endpoint;
79:    }
81:    java.net.InetAddress[] resolved;
82:    try {
83:      resolved = java.net.InetAddress.getAllByName(host);
84:    } catch (java.net.UnknownHostException unresolvable) {
85:      throw new IllegalArgumentException(name + " does not resolve", unresolvable);
86:    }
87:    if (resolved.length == 0) {
88:      throw new IllegalArgumentException(name + " does not resolve");
89:    }
90:    for (java.net.InetAddress address : resolved) {
94:      if (isInternal(address)) {
95:        throw new IllegalArgumentException(
96:            name + " resolves to an address inside the deployment's own network");
97:      }
98:    }
99:    return endpoint;

# 강한 쪽의 프로덕션 호출처
SesProviderProperties.java:27:    NotificationEndpoints.requireExternallyRoutable(endpoint, "SES endpoint", true);
WebhookSubscription.java:49:    NotificationEndpoints.requireExternallyRoutable(target, "webhook target", trusted);
#   그중 웹푸시: 0
# 값 타입이 두 공개 함수 중 하나라도 부르는 줄: 0

# 호출처 도달을 고정하려고 만든 테스트가, 무엇을 목록으로 들고 있는가
17: * <p>{@code EndpointRoutabilityTest} already proves {@code requireExternallyRoutable} rejects the
18: * metadata service, RFC 1918, link-local and the rest. It proved that for months while the function
19: * had no caller: both sites it was written for — a webhook target and an SES endpoint — kept
20: * calling {@code requireSecureOrLoopback}, which reads the scheme and nothing else. A green test on
21: * a control nothing invokes is the shape this repository keeps finding, and testing the helper
22: * again would not have caught it.
37:  @DisplayName("a webhook target on the cloud metadata service is refused")
45:  @DisplayName("a webhook target inside the deployment's own network is refused")
54:  @DisplayName("a webhook target carrying userinfo is refused")
68:  @DisplayName("an SES endpoint inside the deployment's own network is refused")
82:  @DisplayName("a client-supplied webhook target on the loopback interface is refused")
95:  @DisplayName("a client-supplied webhook target on 127.0.0.1 is refused")
106:  @DisplayName("loopback stays available, because local and contract profiles address it")
#   그 파일에서 WebPush 를 언급하는 줄: 0
