1 /* 2 * Copyright (C) 2019, Google LLC. 3 * and other copyright owners as documented in the project's IP log. 4 * 5 * This program and the accompanying materials are made available 6 * under the terms of the Eclipse Distribution License v1.0 which 7 * accompanies this distribution, is reproduced below, and is 8 * available at http://www.eclipse.org/org/documents/edl-v10.php 9 * 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials provided 22 * with the distribution. 23 * 24 * - Neither the name of the Eclipse Foundation, Inc. nor the 25 * names of its contributors may be used to endorse or promote 26 * products derived from this software without specific prior 27 * written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 30 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 31 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 32 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 34 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 */ 43 44 package org.eclipse.jgit.transport; 45 46 import java.text.MessageFormat; 47 48 import org.eclipse.jgit.annotations.Nullable; 49 import org.eclipse.jgit.errors.PackProtocolException; 50 import org.eclipse.jgit.internal.JGitText; 51 52 /** 53 * Represents either a filter specified in a protocol "filter" line, or a 54 * placeholder to indicate no filtering. 55 * 56 * @since 5.4 57 */ 58 public final class FilterSpec { 59 60 private final long blobLimit; 61 62 private final long treeDepthLimit; 63 64 private FilterSpec(long blobLimit, long treeDepthLimit) { 65 this.blobLimit = blobLimit; 66 this.treeDepthLimit = treeDepthLimit; 67 } 68 69 /** 70 * Process the content of "filter" line from the protocol. It has a shape 71 * like: 72 * 73 * <ul> 74 * <li>"blob:none" 75 * <li>"blob:limit=N", with N >= 0 76 * <li>"tree:DEPTH", with DEPTH >= 0 77 * </ul> 78 * 79 * @param filterLine 80 * the content of the "filter" line in the protocol 81 * @return a FilterSpec representing the given filter 82 * @throws PackProtocolException 83 * invalid filter because due to unrecognized format or 84 * negative/non-numeric filter. 85 */ 86 public static FilterSpec fromFilterLine(String filterLine) 87 throws PackProtocolException { 88 if (filterLine.equals("blob:none")) { //$NON-NLS-1$ 89 return FilterSpec.withBlobLimit(0); 90 } else if (filterLine.startsWith("blob:limit=")) { //$NON-NLS-1$ 91 long blobLimit = -1; 92 try { 93 blobLimit = Long 94 .parseLong(filterLine.substring("blob:limit=".length())); //$NON-NLS-1$ 95 } catch (NumberFormatException e) { 96 // Do not change blobLimit so that we throw a 97 // PackProtocolException later. 98 } 99 if (blobLimit >= 0) { 100 return FilterSpec.withBlobLimit(blobLimit); 101 } 102 } else if (filterLine.startsWith("tree:")) { //$NON-NLS-1$ 103 long treeDepthLimit = -1; 104 try { 105 treeDepthLimit = Long 106 .parseLong(filterLine.substring("tree:".length())); //$NON-NLS-1$ 107 } catch (NumberFormatException e) { 108 // Do not change blobLimit so that we throw a 109 // PackProtocolException later. 110 } 111 if (treeDepthLimit >= 0) { 112 return FilterSpec.withTreeDepthLimit(treeDepthLimit); 113 } 114 } 115 116 // Did not match any known filter format. 117 throw new PackProtocolException( 118 MessageFormat.format(JGitText.get().invalidFilter, filterLine)); 119 } 120 121 /** 122 * @param blobLimit 123 * the blob limit in a "blob:[limit]" or "blob:none" filter line 124 * @return a filter spec which filters blobs above a certain size 125 */ 126 static FilterSpec withBlobLimit(long blobLimit) { 127 if (blobLimit < 0) { 128 throw new IllegalArgumentException( 129 "blobLimit cannot be negative: " + blobLimit); //$NON-NLS-1$ 130 } 131 return new FilterSpec(blobLimit, -1); 132 } 133 134 /** 135 * @param treeDepthLimit 136 * the tree depth limit in a "tree:[depth]" filter line 137 * @return a filter spec which filters blobs and trees beyond a certain tree 138 * depth 139 */ 140 static FilterSpec withTreeDepthLimit(long treeDepthLimit) { 141 if (treeDepthLimit < 0) { 142 throw new IllegalArgumentException( 143 "treeDepthLimit cannot be negative: " + treeDepthLimit); //$NON-NLS-1$ 144 } 145 return new FilterSpec(-1, treeDepthLimit); 146 } 147 148 /** 149 * A placeholder that indicates no filtering. 150 */ 151 public static final FilterSpecec.html#FilterSpec">FilterSpec NO_FILTER = new FilterSpec(-1, -1); 152 153 /** 154 * @return -1 if this filter does not filter blobs based on size, or a 155 * non-negative integer representing the max size of blobs to allow 156 */ 157 public long getBlobLimit() { 158 return blobLimit; 159 } 160 161 /** 162 * @return -1 if this filter does not filter blobs and trees based on depth, 163 * or a non-negative integer representing the max tree depth of 164 * blobs and trees to fetch 165 */ 166 public long getTreeDepthLimit() { 167 return treeDepthLimit; 168 } 169 170 /** 171 * @return true if this filter doesn't filter out anything 172 */ 173 public boolean isNoOp() { 174 return blobLimit == -1 && treeDepthLimit == -1; 175 } 176 177 /** 178 * @return the filter line which describes this spec, e.g. "filter blob:limit=42" 179 */ 180 @Nullable 181 public String filterLine() { 182 if (blobLimit == 0) { 183 return GitProtocolConstants.OPTION_FILTER + " blob:none"; //$NON-NLS-1$ 184 } 185 186 if (blobLimit > 0) { 187 return GitProtocolConstants.OPTION_FILTER + " blob:limit=" + blobLimit; //$NON-NLS-1$ 188 } 189 190 return null; 191 } 192 }