jdk/src/java.base/share/classes/java/io/ObjectInputFilter.java
author rriggs
Tue, 04 Oct 2016 13:45:42 -0400
changeset 41230 0a8c1ba2b6fb
child 42223 a55f957f6e4e
permissions -rw-r--r--
8155760: Implement Serialization Filtering 8166739: Improve extensibility of ObjectInputFilter information passed to the filter Reviewed-by: dfuchs, chegar, briangoetz, plevart
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
41230
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
     1
/*
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
     2
 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
     4
 *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    10
 *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    15
 * accompanied this code).
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    16
 *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    20
 *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    23
 * questions.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    24
 */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    25
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    26
package java.io;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    27
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    28
import java.security.AccessController;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    29
import java.security.PrivilegedAction;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    30
import java.security.Security;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    31
import java.util.ArrayList;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    32
import java.util.List;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    33
import java.util.Objects;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    34
import java.util.Optional;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    35
import java.util.function.Function;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    36
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    37
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    38
/**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    39
 * Filter classes, array lengths, and graph metrics during deserialization.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    40
 * If set on an {@link ObjectInputStream}, the {@link #checkInput checkInput(FilterInfo)}
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    41
 * method is called to validate classes, the length of each array,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    42
 * the number of objects being read from the stream, the depth of the graph,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    43
 * and the total number of bytes read from the stream.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    44
 * <p>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    45
 * A filter can be set via {@link ObjectInputStream#setObjectInputFilter setObjectInputFilter}
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    46
 * for an individual ObjectInputStream.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    47
 * A filter can be set via {@link Config#setSerialFilter(ObjectInputFilter) Config.setSerialFilter}
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    48
 * to affect every {@code ObjectInputStream} that does not otherwise set a filter.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    49
 * <p>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    50
 * A filter determines whether the arguments are {@link Status#ALLOWED ALLOWED}
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    51
 * or {@link Status#REJECTED REJECTED} and should return the appropriate status.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    52
 * If the filter cannot determine the status it should return
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    53
 * {@link Status#UNDECIDED UNDECIDED}.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    54
 * Filters should be designed for the specific use case and expected types.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    55
 * A filter designed for a particular use may be passed a class that is outside
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    56
 * of the scope of the filter. If the purpose of the filter is to black-list classes
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    57
 * then it can reject a candidate class that matches and report UNDECIDED for others.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    58
 * A filter may be called with class equals {@code null}, {@code arrayLength} equal -1,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    59
 * the depth, number of references, and stream size and return a status
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    60
 * that reflects only one or only some of the values.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    61
 * This allows a filter to specific about the choice it is reporting and
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    62
 * to use other filters without forcing either allowed or rejected status.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    63
 *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    64
 * <p>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    65
 * Typically, a custom filter should check if a process-wide filter
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    66
 * is configured and defer to it if so. For example,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    67
 * <pre>{@code
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    68
 * ObjectInputFilter.Status checkInput(FilterInfo info) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    69
 *     ObjectInputFilter serialFilter = ObjectInputFilter.Config.getSerialFilter();
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    70
 *     if (serialFilter != null) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    71
 *         ObjectInputFilter.Status status = serialFilter.checkInput(info);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    72
 *         if (status != ObjectInputFilter.Status.UNDECIDED) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    73
 *             // The process-wide filter overrides this filter
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    74
 *             return status;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    75
 *         }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    76
 *     }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    77
 *     if (info.serialClass() != null &&
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    78
 *         Remote.class.isAssignableFrom(info.serialClass())) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    79
 *         return Status.REJECTED;      // Do not allow Remote objects
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    80
 *     }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    81
 *     return Status.UNDECIDED;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    82
 * }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    83
 *}</pre>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    84
 * <p>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    85
 * Unless otherwise noted, passing a {@code null} argument to a
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    86
 * method in this interface and its nested classes will cause a
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    87
 * {@link NullPointerException} to be thrown.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    88
 *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    89
 * @see ObjectInputStream#setObjectInputFilter(ObjectInputFilter)
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    90
 * @since 9
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    91
 */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    92
@FunctionalInterface
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    93
public interface ObjectInputFilter {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    94
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    95
    /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    96
     * Check the class, array length, number of object references, depth,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    97
     * stream size, and other available filtering information.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    98
     * Implementations of this method check the contents of the object graph being created
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
    99
     * during deserialization. The filter returns {@link Status#ALLOWED Status.ALLOWED},
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   100
     * {@link Status#REJECTED Status.REJECTED}, or {@link Status#UNDECIDED Status.UNDECIDED}.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   101
     *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   102
     * @param filterInfo provides information about the current object being deserialized,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   103
     *             if any, and the status of the {@link ObjectInputStream}
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   104
     * @return  {@link Status#ALLOWED Status.ALLOWED} if accepted,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   105
     *          {@link Status#REJECTED Status.REJECTED} if rejected,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   106
     *          {@link Status#UNDECIDED Status.UNDECIDED} if undecided.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   107
     * @since 9
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   108
     */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   109
    Status checkInput(FilterInfo filterInfo);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   110
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   111
    /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   112
     * FilterInfo provides access to information about the current object
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   113
     * being deserialized and the status of the {@link ObjectInputStream}.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   114
     * @since 9
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   115
     */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   116
    interface FilterInfo {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   117
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   118
         * The class of an object being deserialized.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   119
         * For arrays, it is the array type.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   120
         * For example, the array class name of a 2 dimensional array of strings is
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   121
         * "{@code [[Ljava.lang.String;}".
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   122
         * To check the array's element type, iteratively use
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   123
         * {@link Class#getComponentType() Class.getComponentType} while the result
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   124
         * is an array and then check the class.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   125
         * The {@code serialClass is null} in the case where a new object is not being
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   126
         * created and to give the filter a chance to check the depth, number of
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   127
         * references to existing objects, and the stream size.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   128
         *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   129
         * @return class of an object being deserialized; may be null
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   130
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   131
        Class<?> serialClass();
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   132
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   133
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   134
         * The number of array elements when deserializing an array of the class.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   135
         *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   136
         * @return the non-negative number of array elements when deserializing
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   137
         * an array of the class, otherwise -1
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   138
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   139
        long arrayLength();
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   140
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   141
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   142
         * The current depth.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   143
         * The depth starts at {@code 1} and increases for each nested object and
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   144
         * decrements when each nested object returns.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   145
         *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   146
         * @return the current depth
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   147
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   148
        long depth();
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   149
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   150
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   151
         * The current number of object references.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   152
         *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   153
         * @return the non-negative current number of object references
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   154
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   155
        long references();
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   156
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   157
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   158
         * The current number of bytes consumed.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   159
         * @implSpec  {@code streamBytes} is implementation specific
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   160
         * and may not be directly related to the object in the stream
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   161
         * that caused the callback.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   162
         *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   163
         * @return the non-negative current number of bytes consumed
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   164
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   165
        long streamBytes();
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   166
    }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   167
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   168
    /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   169
     * The status of a check on the class, array length, number of references,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   170
     * depth, and stream size.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   171
     *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   172
     * @since 9
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   173
     */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   174
    enum Status {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   175
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   176
         * The status is undecided, not allowed and not rejected.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   177
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   178
        UNDECIDED,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   179
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   180
         * The status is allowed.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   181
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   182
        ALLOWED,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   183
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   184
         * The status is rejected.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   185
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   186
        REJECTED;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   187
    }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   188
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   189
    /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   190
     * A utility class to set and get the process-wide filter or create a filter
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   191
     * from a pattern string. If a process-wide filter is set, it will be
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   192
     * used for each {@link ObjectInputStream} that does not set its own filter.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   193
     * <p>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   194
     * When setting the filter, it should be stateless and idempotent,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   195
     * reporting the same result when passed the same arguments.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   196
     * <p>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   197
     * The filter is configured using the {@link java.security.Security}
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   198
     * property {@code jdk.serialFilter} and can be overridden by
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   199
     * the System property {@code jdk.serialFilter}.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   200
     *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   201
     * The syntax is the same as for the {@link #createFilter(String) createFilter} method.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   202
     *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   203
     * @since 9
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   204
     */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   205
    final class Config {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   206
        /* No instances. */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   207
        private Config() {}
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   208
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   209
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   210
         * Lock object for process-wide filter.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   211
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   212
        private final static Object serialFilterLock = new Object();
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   213
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   214
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   215
         * Debug: Logger
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   216
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   217
        private final static System.Logger configLog;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   218
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   219
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   220
         * Logger for debugging.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   221
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   222
        static void filterLog(System.Logger.Level level, String msg, Object... args) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   223
            if (configLog != null) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   224
                configLog.log(level, msg, args);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   225
            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   226
        }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   227
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   228
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   229
         * The name for the process-wide deserialization filter.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   230
         * Used as a system property and a java.security.Security property.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   231
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   232
        private final static String SERIAL_FILTER_PROPNAME = "jdk.serialFilter";
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   233
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   234
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   235
         * The process-wide filter; may be null.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   236
         * Lookup the filter in java.security.Security or
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   237
         * the system property.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   238
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   239
        private final static ObjectInputFilter configuredFilter;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   240
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   241
        static {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   242
            configuredFilter = AccessController
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   243
                    .doPrivileged((PrivilegedAction<ObjectInputFilter>) () -> {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   244
                        String props = System.getProperty(SERIAL_FILTER_PROPNAME);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   245
                        if (props == null) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   246
                            props = Security.getProperty(SERIAL_FILTER_PROPNAME);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   247
                        }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   248
                        if (props != null) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   249
                            System.Logger log =
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   250
                                    System.getLogger("java.io.serialization");
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   251
                            log.log(System.Logger.Level.INFO,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   252
                                    "Creating serialization filter from {0}", props);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   253
                            try {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   254
                                return createFilter(props);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   255
                            } catch (RuntimeException re) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   256
                                log.log(System.Logger.Level.ERROR,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   257
                                        "Error configuring filter: {0}", re);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   258
                            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   259
                        }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   260
                        return null;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   261
                    });
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   262
            configLog = (configuredFilter != null) ? System.getLogger("java.io.serialization") : null;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   263
        }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   264
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   265
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   266
         * Current configured filter.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   267
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   268
        private static ObjectInputFilter serialFilter = configuredFilter;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   269
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   270
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   271
         * Returns the process-wide serialization filter or {@code null} if not configured.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   272
         *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   273
         * @return the process-wide serialization filter or {@code null} if not configured
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   274
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   275
        public static ObjectInputFilter getSerialFilter() {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   276
            synchronized (serialFilterLock) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   277
                return serialFilter;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   278
            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   279
        }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   280
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   281
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   282
         * Set the process-wide filter if it has not already been configured or set.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   283
         *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   284
         * @param filter the serialization filter to set as the process-wide filter; not null
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   285
         * @throws SecurityException if there is security manager and the
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   286
         *       {@code SerializablePermission("serialFilter")} is not granted
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   287
         * @throws IllegalStateException if the filter has already been set {@code non-null}
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   288
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   289
        public static void setSerialFilter(ObjectInputFilter filter) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   290
            Objects.requireNonNull(filter, "filter");
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   291
            SecurityManager sm = System.getSecurityManager();
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   292
            if (sm != null) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   293
                sm.checkPermission(ObjectStreamConstants.SERIAL_FILTER_PERMISSION);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   294
            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   295
            synchronized (serialFilterLock) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   296
                if (serialFilter != null) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   297
                    throw new IllegalStateException("Serial filter can only be set once");
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   298
                }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   299
                serialFilter = filter;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   300
            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   301
        }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   302
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   303
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   304
         * Returns an ObjectInputFilter from a string of patterns.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   305
         * <p>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   306
         * Patterns are separated by ";" (semicolon). Whitespace is significant and
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   307
         * is considered part of the pattern.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   308
         * If a pattern includes an equals assignment, "{@code =}" it sets a limit.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   309
         * If a limit appears more than once the last value is used.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   310
         * <ul>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   311
         *     <li>maxdepth={@code value} - the maximum depth of a graph</li>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   312
         *     <li>maxrefs={@code value}  - the maximum number of internal references</li>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   313
         *     <li>maxbytes={@code value} - the maximum number of bytes in the input stream</li>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   314
         *     <li>maxarray={@code value} - the maximum array length allowed</li>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   315
         * </ul>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   316
         * <p>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   317
         * Other patterns match or reject class or package name
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   318
         * as returned from {@link Class#getName() Class.getName()} and
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   319
         * if an optional module name is present
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   320
         * {@link java.lang.reflect.Module#getName() class.getModule().getName()}.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   321
         * Note that for arrays the element type is used in the pattern,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   322
         * not the array type.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   323
         * <ul>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   324
         * <li>If the pattern starts with "!", the class is rejected if the remaining pattern is matched;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   325
         *     otherwise the class is allowed if the pattern matches.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   326
         * <li>If the pattern contains "/", the non-empty prefix up to the "/" is the module name;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   327
         *     if the module name matches the module name of the class then
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   328
         *     the remaining pattern is matched with the class name.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   329
         *     If there is no "/", the module name is not compared.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   330
         * <li>If the pattern ends with ".**" it matches any class in the package and all subpackages.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   331
         * <li>If the pattern ends with ".*" it matches any class in the package.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   332
         * <li>If the pattern ends with "*", it matches any class with the pattern as a prefix.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   333
         * <li>If the pattern is equal to the class name, it matches.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   334
         * <li>Otherwise, the pattern is not matched.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   335
         * </ul>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   336
         * <p>
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   337
         * The resulting filter performs the limit checks and then
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   338
         * tries to match the class, if any. If any of the limits are exceeded,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   339
         * the filter returns {@link Status#REJECTED Status.REJECTED}.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   340
         * If the class is an array type, the class to be matched is the element type.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   341
         * Arrays of any number of dimensions are treated the same as the element type.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   342
         * For example, a pattern of "{@code !example.Foo}",
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   343
         * rejects creation of any instance or array of {@code example.Foo}.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   344
         * The first pattern that matches, working from left to right, determines
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   345
         * the {@link Status#ALLOWED Status.ALLOWED}
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   346
         * or {@link Status#REJECTED Status.REJECTED} result.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   347
         * If nothing matches, the result is {@link Status#UNDECIDED Status.UNDECIDED}.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   348
         *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   349
         * @param pattern the pattern string to parse; not null
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   350
         * @return a filter to check a class being deserialized; may be null;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   351
         *          {@code null} if no patterns
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   352
         * @throws IllegalArgumentException
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   353
         *                if a limit is missing the name, or the long value
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   354
         *                is not a number or is negative,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   355
         *                or the module name is missing if the pattern contains "/"
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   356
         *                or if the package is missing for ".*" and ".**"
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   357
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   358
        public static ObjectInputFilter createFilter(String pattern) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   359
            Objects.requireNonNull(pattern, "pattern");
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   360
            return Global.createFilter(pattern);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   361
        }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   362
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   363
        /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   364
         * Implementation of ObjectInputFilter that performs the checks of
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   365
         * the process-wide serialization filter. If configured, it will be
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   366
         * used for all ObjectInputStreams that do not set their own filters.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   367
         *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   368
         */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   369
        final static class Global implements ObjectInputFilter {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   370
            /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   371
             * The pattern used to create the filter.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   372
             */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   373
            private final String pattern;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   374
            /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   375
             * The list of class filters.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   376
             */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   377
            private final List<Function<Class<?>, Status>> filters;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   378
            /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   379
             * Maximum allowed bytes in the stream.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   380
             */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   381
            private long maxStreamBytes;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   382
            /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   383
             * Maximum depth of the graph allowed.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   384
             */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   385
            private long maxDepth;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   386
            /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   387
             * Maximum number of references in a graph.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   388
             */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   389
            private long maxReferences;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   390
            /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   391
             * Maximum length of any array.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   392
             */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   393
            private long maxArrayLength;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   394
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   395
            /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   396
             * Returns an ObjectInputFilter from a string of patterns.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   397
             *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   398
             * @param pattern the pattern string to parse
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   399
             * @return a filter to check a class being deserialized; not null
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   400
             * @throws IllegalArgumentException if the parameter is malformed
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   401
             *                if the pattern is missing the name, the long value
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   402
             *                is not a number or is negative.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   403
             */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   404
            static ObjectInputFilter createFilter(String pattern) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   405
                Global filter = new Global(pattern);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   406
                return filter.isEmpty() ? null : filter;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   407
            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   408
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   409
            /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   410
             * Construct a new filter from the pattern String.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   411
             *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   412
             * @param pattern a pattern string of filters
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   413
             * @throws IllegalArgumentException if the pattern is malformed
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   414
             */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   415
            private Global(String pattern) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   416
                this.pattern = pattern;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   417
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   418
                maxArrayLength = Long.MAX_VALUE; // Default values are unlimited
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   419
                maxDepth = Long.MAX_VALUE;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   420
                maxReferences = Long.MAX_VALUE;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   421
                maxStreamBytes = Long.MAX_VALUE;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   422
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   423
                String[] patterns = pattern.split(";");
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   424
                filters = new ArrayList<>(patterns.length);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   425
                for (int i = 0; i < patterns.length; i++) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   426
                    String p = patterns[i];
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   427
                    int nameLen = p.length();
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   428
                    if (nameLen == 0) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   429
                        continue;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   430
                    }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   431
                    if (parseLimit(p)) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   432
                        // If the pattern contained a limit setting, i.e. type=value
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   433
                        continue;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   434
                    }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   435
                    boolean negate = p.charAt(0) == '!';
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   436
                    int poffset = negate ? 1 : 0;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   437
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   438
                    // isolate module name, if any
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   439
                    int slash = p.indexOf('/', poffset);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   440
                    if (slash == poffset) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   441
                        throw new IllegalArgumentException("module name is missing in: \"" + pattern + "\"");
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   442
                    }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   443
                    final String moduleName = (slash >= 0) ? p.substring(poffset, slash) : null;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   444
                    poffset = (slash >= 0) ? slash + 1 : poffset;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   445
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   446
                    final Function<Class<?>, Status> patternFilter;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   447
                    if (p.endsWith("*")) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   448
                        // Wildcard cases
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   449
                        if (p.endsWith(".*")) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   450
                            // Pattern is a package name with a wildcard
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   451
                            final String pkg = p.substring(poffset, nameLen - 1);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   452
                            if (pkg.length() < 2) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   453
                                throw new IllegalArgumentException("package missing in: \"" + pattern + "\"");
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   454
                            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   455
                            if (negate) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   456
                                // A Function that fails if the class starts with the pattern, otherwise don't care
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   457
                                patternFilter = c -> matchesPackage(c, pkg) ? Status.REJECTED : Status.UNDECIDED;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   458
                            } else {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   459
                                // A Function that succeeds if the class starts with the pattern, otherwise don't care
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   460
                                patternFilter = c -> matchesPackage(c, pkg) ? Status.ALLOWED : Status.UNDECIDED;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   461
                            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   462
                        } else if (p.endsWith(".**")) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   463
                            // Pattern is a package prefix with a double wildcard
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   464
                            final String pkgs = p.substring(poffset, nameLen - 2);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   465
                            if (pkgs.length() < 2) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   466
                                throw new IllegalArgumentException("package missing in: \"" + pattern + "\"");
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   467
                            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   468
                            if (negate) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   469
                                // A Function that fails if the class starts with the pattern, otherwise don't care
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   470
                                patternFilter = c -> c.getName().startsWith(pkgs) ? Status.REJECTED : Status.UNDECIDED;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   471
                            } else {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   472
                                // A Function that succeeds if the class starts with the pattern, otherwise don't care
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   473
                                patternFilter = c -> c.getName().startsWith(pkgs) ? Status.ALLOWED : Status.UNDECIDED;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   474
                            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   475
                        } else {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   476
                            // Pattern is a classname (possibly empty) with a trailing wildcard
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   477
                            final String className = p.substring(poffset, nameLen - 1);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   478
                            if (negate) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   479
                                // A Function that fails if the class starts with the pattern, otherwise don't care
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   480
                                patternFilter = c -> c.getName().startsWith(className) ? Status.REJECTED : Status.UNDECIDED;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   481
                            } else {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   482
                                // A Function that succeeds if the class starts with the pattern, otherwise don't care
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   483
                                patternFilter = c -> c.getName().startsWith(className) ? Status.ALLOWED : Status.UNDECIDED;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   484
                            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   485
                        }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   486
                    } else {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   487
                        final String name = p.substring(poffset);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   488
                        if (name.isEmpty()) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   489
                            throw new IllegalArgumentException("class or package missing in: \"" + pattern + "\"");
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   490
                        }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   491
                        // Pattern is a class name
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   492
                        if (negate) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   493
                            // A Function that fails if the class equals the pattern, otherwise don't care
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   494
                            patternFilter = c -> c.getName().equals(name) ? Status.REJECTED : Status.UNDECIDED;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   495
                        } else {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   496
                            // A Function that succeeds if the class equals the pattern, otherwise don't care
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   497
                            patternFilter = c -> c.getName().equals(name) ? Status.ALLOWED : Status.UNDECIDED;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   498
                        }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   499
                    }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   500
                    // If there is a moduleName, combine the module name check with the package/class check
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   501
                    if (moduleName == null) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   502
                        filters.add(patternFilter);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   503
                    } else {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   504
                        filters.add(c -> moduleName.equals(c.getModule().getName()) ? patternFilter.apply(c) : Status.UNDECIDED);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   505
                    }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   506
                }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   507
            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   508
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   509
            /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   510
             * Returns if this filter has any checks.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   511
             * @return {@code true} if the filter has any checks, {@code false} otherwise
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   512
             */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   513
            private boolean isEmpty() {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   514
                return filters.isEmpty() &&
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   515
                        maxArrayLength == Long.MAX_VALUE &&
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   516
                        maxDepth == Long.MAX_VALUE &&
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   517
                        maxReferences == Long.MAX_VALUE &&
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   518
                        maxStreamBytes == Long.MAX_VALUE;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   519
            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   520
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   521
            /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   522
             * Parse out a limit for one of maxarray, maxdepth, maxbytes, maxreferences.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   523
             *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   524
             * @param pattern a string with a type name, '=' and a value
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   525
             * @return {@code true} if a limit was parsed, else {@code false}
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   526
             * @throws IllegalArgumentException if the pattern is missing
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   527
             *                the name, the Long value is not a number or is negative.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   528
             */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   529
            private boolean parseLimit(String pattern) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   530
                int eqNdx = pattern.indexOf('=');
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   531
                if (eqNdx < 0) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   532
                    // not a limit pattern
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   533
                    return false;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   534
                }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   535
                String valueString = pattern.substring(eqNdx + 1);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   536
                if (pattern.startsWith("maxdepth=")) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   537
                    maxDepth = parseValue(valueString);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   538
                } else if (pattern.startsWith("maxarray=")) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   539
                    maxArrayLength = parseValue(valueString);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   540
                } else if (pattern.startsWith("maxrefs=")) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   541
                    maxReferences = parseValue(valueString);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   542
                } else if (pattern.startsWith("maxbytes=")) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   543
                    maxStreamBytes = parseValue(valueString);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   544
                } else {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   545
                    throw new IllegalArgumentException("unknown limit: " + pattern.substring(0, eqNdx));
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   546
                }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   547
                return true;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   548
            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   549
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   550
            /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   551
             * Parse the value of a limit and check that it is non-negative.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   552
             * @param string inputstring
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   553
             * @return the parsed value
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   554
             * @throws IllegalArgumentException if parsing the value fails or the value is negative
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   555
             */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   556
            private static long parseValue(String string) throws IllegalArgumentException {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   557
                // Parse a Long from after the '=' to the end
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   558
                long value = Long.parseLong(string);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   559
                if (value < 0) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   560
                    throw new IllegalArgumentException("negative limit: " + string);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   561
                }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   562
                return value;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   563
            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   564
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   565
            /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   566
             * {@inheritDoc}
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   567
             */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   568
            @Override
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   569
            public Status checkInput(FilterInfo filterInfo) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   570
                if (filterInfo.references() < 0
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   571
                        || filterInfo.depth() < 0
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   572
                        || filterInfo.streamBytes() < 0
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   573
                        || filterInfo.references() > maxReferences
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   574
                        || filterInfo.depth() > maxDepth
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   575
                        || filterInfo.streamBytes() > maxStreamBytes) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   576
                    return Status.REJECTED;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   577
                }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   578
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   579
                Class<?> clazz = filterInfo.serialClass();
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   580
                if (clazz != null) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   581
                    if (clazz.isArray()) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   582
                        if (filterInfo.arrayLength() >= 0 && filterInfo.arrayLength() > maxArrayLength) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   583
                            // array length is too big
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   584
                            return Status.REJECTED;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   585
                        }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   586
                        do {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   587
                            // Arrays are decided based on the component type
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   588
                            clazz = clazz.getComponentType();
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   589
                        } while (clazz.isArray());
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   590
                    }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   591
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   592
                    if (clazz.isPrimitive())  {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   593
                        // Primitive types are undecided; let someone else decide
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   594
                        return Status.UNDECIDED;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   595
                    } else {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   596
                        // Find any filter that allowed or rejected the class
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   597
                        final Class<?> cl = clazz;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   598
                        Optional<Status> status = filters.stream()
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   599
                                .map(f -> f.apply(cl))
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   600
                                .filter(p -> p != Status.UNDECIDED)
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   601
                                .findFirst();
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   602
                        return status.orElse(Status.UNDECIDED);
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   603
                    }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   604
                }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   605
                return Status.UNDECIDED;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   606
            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   607
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   608
            /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   609
             * Returns {@code true} if the class is in the package.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   610
             *
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   611
             * @param c   a class
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   612
             * @param pkg a package name (including the trailing ".")
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   613
             * @return {@code true} if the class is in the package,
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   614
             * otherwise {@code false}
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   615
             */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   616
            private static boolean matchesPackage(Class<?> c, String pkg) {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   617
                String n = c.getName();
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   618
                return n.startsWith(pkg) && n.lastIndexOf('.') == pkg.length() - 1;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   619
            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   620
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   621
            /**
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   622
             * Returns the pattern used to create this filter.
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   623
             * @return the pattern used to create this filter
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   624
             */
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   625
            @Override
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   626
            public String toString() {
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   627
                return pattern;
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   628
            }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   629
        }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   630
    }
0a8c1ba2b6fb 8155760: Implement Serialization Filtering
rriggs
parents:
diff changeset
   631
}