001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.commons.utils;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.net.*;
022
023/**
024 * Various {@link URI}-related utility methods.
025 *
026 * @since 10.0.0
027 */
028public class UriUtils {
029
030   /**
031    * Returns <jk>true</jk> if the specified URI either uses the <js>"https"</js> scheme or targets a loopback
032    * host.
033    *
034    * <p>
035    * A loopback host is one of <js>"localhost"</js> (case-insensitive), <js>"127.0.0.1"</js>, <js>"::1"</js>, or
036    * <js>"[::1]"</js>.  A plaintext (<js>"http"</js>) URI aimed at any other host returns <jk>false</jk>, as does
037    * a <jk>null</jk> or scheme-less (malformed) URI.  This is the check to make before transmitting anything
038    * sensitive to a caller-configured endpoint so that a plaintext transport is only tolerated for local
039    * development.
040    *
041    * @param uri The URI to check.  Can be <jk>null</jk> (returns <jk>false</jk>).
042    * @return <jk>true</jk> if the URI is <js>"https"</js> or targets a loopback host.
043    */
044   public static boolean isSecureOrLoopback(URI uri) {
045      if (uri == null)
046         return false;
047      if (eqic("https", uri.getScheme()))
048         return true;
049      var host = uri.getHost();
050      return host != null && (eq(host, "127.0.0.1") || eqic(host, "localhost") || eqa(host, "[::1]", "::1"));
051   }
052
053   /**
054    * Throwing variant of {@link #isSecureOrLoopback(URI)}.
055    *
056    * @param uri The URI to validate.  Can be <jk>null</jk> (rejected).
057    * @return The validated URI (for fluent use).
058    * @throws IllegalArgumentException If the URI is not <js>"https"</js> and does not target a loopback host.
059    */
060   public static URI assertSecureOrLoopback(URI uri) {
061      if (! isSecureOrLoopback(uri))
062         throw iaex("URI must use https or target a loopback host: %s", uri);
063      return uri;
064   }
065
066   /**
067    * Constructor.
068    */
069   protected UriUtils() {}
070}