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.rest.server.view;
018
019/**
020 * Shared template-name checks applied by the view bridges before a name reaches a templating engine.
021 *
022 * <p>
023 * A template name is a path relative to the bridge's configured base path.  Names that carry a URL scheme
024 * (or any {@code :}) or a backslash are never valid, and raw-served names must end in one of the extensions
025 * registered for the engine.
026 *
027 * @since 10.0.0
028 */
029public final class ViewTemplateNames {
030
031   private ViewTemplateNames() {}
032
033   /**
034    * Returns {@code true} if the name is free of URL-scheme and path-separator tricks.
035    *
036    * @param name The template name.  May be {@code null}.
037    * @return {@code false} if the name contains {@code :}, a backslash, or a control character.
038    */
039   public static boolean isPlainName(String name) {
040      if (name == null)
041         return true;
042      for (var i = 0; i < name.length(); i++) {
043         var c = name.charAt(i);
044         if (c == ':' || c == '\\' || c <= 0x1f || c == 0x7f)
045            return false;
046      }
047      return true;
048   }
049
050   /**
051    * Returns {@code true} if the name ends with one of the allowed extensions.
052    *
053    * @param name The template name.  Must not be {@code null}.
054    * @param extensions The allowed extensions, including the leading dot (e.g. {@code ".ftlh"}).
055    * @return {@code true} if the name has an allowed extension.
056    */
057   public static boolean hasAllowedExtension(String name, String... extensions) {
058      var lower = name.toLowerCase();
059      for (var e : extensions)
060         if (lower.endsWith(e))
061            return true;
062      return false;
063   }
064
065   /**
066    * Validates a template name for the typed-view path, throwing if it is not a plain name.
067    *
068    * @param name The template name.
069    * @throws IllegalArgumentException If the name is not plain.
070    */
071   public static void requirePlainName(String name) {
072      if (! isPlainName(name))
073         throw new IllegalArgumentException("Template name contains a scheme or illegal character: " + name);
074   }
075}